FORM BANNER
FORM BANNER

CD2001C – Analítica para Negocios: De Los Datos a las Decisiones Febrero – Junio 2024

Entregable 2 – Evidencia 1

Situación Problema 1: Rotación de Personal

Explorar, definir, y describir cuáles son los principales factores del clima organizacional de FORM que propician la satisfacción y/o no satisfacción de trabajar en dicha empresa.

La rotación de personal se ha identificado como el desafío más crítico que enfrenta FORM en el presente. A pesar de nuestros esfuerzos continuos para crear un ambiente laboral atractivo y retener a nuestros valiosos empleados, nos encontramos con una tasa de rotación especialmente alta entre los operadores. Este fenómeno no solo afecta la continuidad y la eficiencia de nuestras operaciones, sino que también incrementa los costos asociados con el reclutamiento y la capacitación de nuevo personal.

  • Principales Puntos:
    • La estabilidad familiar y las condiciones laborales son factores significativos que influyen en la decisión de los empleados de permanecer en la empresa.
    • Los jóvenes, especialmente aquellos sin compromisos familiares, tienden a buscar oportunidades de desarrollo profesional fuera de FORM.
    • Es crucial mejorar nuestras estrategias de reclutamiento y retención para abordar las causas subyacentes de la rotación de personal.

Situación Problema 2: Predicción de Demanda

Explorar, desarrollar, y describir la(s) posible(s) estrategia(s) de predicción de la demanada de productos fabricados por la empresa FORM.

La predicción precisa de la demanda representa un desafío igualmente significativo para FORM, dada la variabilidad inherente en la producción y venta de autopartes. La habilidad para anticipar con exactitud cuántas unidades de un determinado componente serán necesarias es crucial para optimizar nuestros procesos de producción y empaque, y para asegurar que se maximice la eficiencia en el uso de recursos.

  • Principales Puntos:
    • La naturaleza fluctuante de la demanda automotriz complica la planificación y gestión de inventarios.
    • Es esencial desarrollar herramientas y procesos más sofisticados para mejorar la precisión en nuestras predicciones de demanda.
    • La adaptabilidad y la capacidad de responder rápidamente a los cambios en el mercado son fundamentales para mantener nuestra competitividad.

Análisis Descriptivo de los Datos

A partir de las diferentes bases de datos compartidas por la empresa FORM y las industrias relacionadas con dicha empresa, seleccionar al menos 1 situación problema y elaborar lo siguiente:

Librerías necesarias

library(imputeTS)
library(xts)
library(zoo)
library(tseries)
library(stats)
library(forecast)
library(astsa)
library(corrplot)
library(wordcloud)
library(tidytext)
library(AER)
library(vars)
library(dynlm)
library(mFilter)
library(TSstudio)
library(tidyverse)
library(sarima)
library(readr)
library(readxl)
library(heatmaply)
library(dplyr)
library(ggplot2)
library(psych)
library(tidyr)
library(readtext)
library(syuzhet)
library(RColorBrewer)
library(tm)
library(caret)
library(MASS)
library(rpart)
library(rpart.plot)
library(party)
library(gmodels)
library(knitr)
library(cluster)    
library(e1071)
library(pROC)
library(ISLR)
library(gridExtra)
library(car)
library(DataExplorer)
library(randomForest)
library(class)
library(factoextra)
library(purrr)

Preguntas de Análisis

Elaborar 4-6 preguntas relacionadas con la situación problema seleccionada que se puedan responder mediante el análisis de datos.

Situación Problema 1: Rotación de Personal - ¿Qué está causando la rotación de personal tan alta? - ¿Existe algún momento del año donde se den más bajas dentro de la empresa? - ¿Cómo se siente la gente dentro de su trabajo actual? - ¿Qué factor ayuda a que el personal dure más tiempo dentro de la empresa? - ¿En qué parte de la empresa el trabajador se siente más inconforme y cuál es su perfil?

Situación Problema 2: Predicción de Demanda - ¿Cuáles son los patrones históricos de demanda de empaques de cartón para autopartes en los mercados objetivo de la empresa FORM, y cómo varían estos patrones según la temporada, el tipo de autoparte, y las regiones geográficas? - ⁠¿Cómo impactan los lanzamientos de nuevos modelos de vehículos y las tendencias en la industria automotriz en la demanda de diferentes tipos de empaques de cartón para autopartes? - ⁠¿Cuál ha sido el efecto de las campañas de marketing y las actividades promocionales de la empresa FORM sobre la demanda de sus productos en el pasado? - ⁠¿Cómo impactan algunas variables externas de carácter macroeconómico a las ventas de la empresa?

Pronosticos y Nearshoring

  • Mediante el uso de visualización de datos describir el posible impacto del fenómeno nearshoring sobre el desempeño de la empresa FORM.

En un mundo empresarial cada vez más globalizado y competitivo, las organizaciones buscan constantemente estrategias innovadoras para optimizar sus operaciones y mantenerse a la vanguardia de sus respectivas industrias. Una de estas estrategias que ha ganado protagonismo en los últimos años es el “Nearshoring”, un enfoque de outsourcing que consiste en delegar actividades y servicios a proveedores ubicados en países geográficamente cercanos. En este contexto, México emerge como un destino atractivo para el “Nearshoring”, gracias a su ubicación estratégica, recurso humano capacitado y condiciones económicas favorables.

México tiene una ubicación geográfica privilegiada, compartiendo fronteras con Estados Unidos y siendo parte del Tratado de Libre Comercio de América del Norte (TLCAN), hoy T-MEC, lo que facilita el acceso a uno de los mercados más grandes y dinámicos. del mundo. Esta proximidad geográfica no sólo reduce los costos y tiempos de transporte, sino que también facilita la comunicación y colaboración en tiempo real entre las empresas matrices y sus socios de nearshoring. Además, México ha establecido una red de acuerdos comerciales que brindan ventajas arancelarias y facilitan el flujo de bienes, brindando una plataforma atractiva para operaciones de subcontratación.

El país también cuenta con una fuerza laboral altamente calificada y diversificada, que va desde ingenieros y profesionales de tecnología hasta expertos en manufactura y servicios financieros. Los costos laborales en México son competitivos en comparación con otros destinos de subcontratación, lo que permite a las empresas obtener mayor valor agregado a un menor costo. Además, el continuo crecimiento en educación y formación ha impulsado la formación de profesionales altamente cualificados, lo que garantiza la disponibilidad del talento necesario para cubrir las demandas del “Nearshoring”. Todo esto ha hecho que en los últimos años México haya sido testigo del acelerado proceso de Nearshoring, donde muchas empresas internacionales han decidido invertir en nuestro país para abrir megafábricas. Recientemente destaca el caso de Testa y su gigafábrica en el estado de Nuevo León. . Este fenómeno podría traer grandes beneficios a nuestro país por todas las pérdidas económicas que conlleva. Según el Global Business Council (CEG) (2023), el nearshoring podría generar hasta 4 millones de empleos en territorio mexicano para 2030, recibiendo entre 30 y 50 mil millones de dólares anuales, además, el mismo estudio señala que este fenómeno puede ser responsable de aumentando el PIB de México hasta en un 2.5% en los próximos 6 años. Por lo tanto, es muy importante analizar y comprender este fenómeno a través del análisis estadístico de datos históricos de Inversión Extranjera Directa y algunas variables macroeconómicas que están estrechamente relacionadas con dicha variable dependiente.

Pronosticar el evento de Nearshoring.

Bases de Datos de Nearshoring

setwd("../databases/nearshoring")
df=read.csv("quarter_economic_data.csv")

summary(df)
##       Year         Quarter      New_FDI_Inflows Exchange_Rate  
##  Min.   :2006   Min.   :1.000   Min.   :-2433   Min.   :10.82  
##  1st Qu.:2010   1st Qu.:1.000   1st Qu.: 1934   1st Qu.:12.65  
##  Median :2014   Median :2.000   Median : 2605   Median :13.65  
##  Mean   :2014   Mean   :2.478   Mean   : 3001   Mean   :15.59  
##  3rd Qu.:2018   3rd Qu.:3.000   3rd Qu.: 3750   3rd Qu.:19.26  
##  Max.   :2023   Max.   :4.000   Max.   :15445   Max.   :21.60  
##                                                                
##  new_fdi_inflows_mxn log_new_fdi_inflows_mxn new_foreign_businesses
##  Min.   :-37081      Min.   :-10.52          Min.   : 1.000        
##  1st Qu.: 33164      1st Qu.: 10.41          1st Qu.: 5.000        
##  Median : 46617      Median : 10.75          Median : 8.000        
##  Mean   : 51775      Mean   : 10.10          Mean   : 8.145        
##  3rd Qu.: 65069      3rd Qu.: 11.08          3rd Qu.:11.000        
##  Max.   :237466      Max.   : 12.38          Max.   :21.000        
##                                                                    
##  Población_Economicamente_Activa Poblacion_ocupada_industria_manufacturera
##  Min.   :2601760                 Min.   :13942848                         
##  1st Qu.:3404623                 1st Qu.:15463066                         
##  Median :3433560                 Median :16917276                         
##  Mean   :3440431                 Mean   :16696687                         
##  3rd Qu.:3525446                 3rd Qu.:17975390                         
##  Max.   :3597380                 Max.   :19516476                         
##  NA's   :20                      NA's   :20                               
##  Poblacion_ocupada   Tasa_de_ocupacion_industria_manufacturera
##  Min.   : 89430135   Min.   : 928.3                           
##  1st Qu.: 96999416   1st Qu.:1002.1                           
##  Median :102344068   Median :1040.2                           
##  Mean   :102769315   Mean   :1028.8                           
##  3rd Qu.:107429516   3rd Qu.:1062.1                           
##  Max.   :116984252   Max.   :1082.7                           
##  NA's   :20          NA's   :20
str(df)
## 'data.frame':    69 obs. of  11 variables:
##  $ Year                                     : int  2006 2006 2006 2006 2007 2007 2007 2007 2008 2008 ...
##  $ Quarter                                  : int  1 2 3 4 1 2 3 4 1 2 ...
##  $ New_FDI_Inflows                          : num  897 2110 1284 2678 3108 ...
##  $ Exchange_Rate                            : num  10.8 10.9 10.9 10.9 10.9 ...
##  $ new_fdi_inflows_mxn                      : num  15471 36790 22338 46617 52252 ...
##  $ log_new_fdi_inflows_mxn                  : num  9.65 10.51 10.01 10.75 10.86 ...
##  $ new_foreign_businesses                   : int  10 8 10 13 4 21 7 5 7 6 ...
##  $ Población_Economicamente_Activa          : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ Poblacion_ocupada_industria_manufacturera: num  NA NA NA NA NA NA NA NA NA NA ...
##  $ Poblacion_ocupada                        : num  NA NA NA NA NA NA NA NA NA NA ...
##  $ Tasa_de_ocupacion_industria_manufacturera: num  NA NA NA NA NA NA NA NA NA NA ...
# Calculamos el número de NA por columna
nas_por_columna <- sapply(df, function(x) sum(is.na(x)))

# Filtramos las columnas que tienen 7 o más NA para eliminarlas
columnas_para_eliminar <- names(nas_por_columna[nas_por_columna >= 7])
df <- df %>% select(-one_of(columnas_para_eliminar))

# Para las columnas restantes, imputamos los NA con la mediana
df <- df %>% mutate(across(.cols = where(~ sum(is.na(.)) < 7), 
                           .fns = ~ ifelse(is.na(.), median(., na.rm = TRUE), .)))

Se realizó una imputación de las variables y se eliminaron aquellas con demasiados valores NAS faltantes.

Analisis de la Base de Nearshoring

summary(df)
##       Year         Quarter      New_FDI_Inflows Exchange_Rate  
##  Min.   :2006   Min.   :1.000   Min.   :-2433   Min.   :10.82  
##  1st Qu.:2010   1st Qu.:1.000   1st Qu.: 1934   1st Qu.:12.65  
##  Median :2014   Median :2.000   Median : 2605   Median :13.65  
##  Mean   :2014   Mean   :2.478   Mean   : 3001   Mean   :15.59  
##  3rd Qu.:2018   3rd Qu.:3.000   3rd Qu.: 3750   3rd Qu.:19.26  
##  Max.   :2023   Max.   :4.000   Max.   :15445   Max.   :21.60  
##  new_fdi_inflows_mxn log_new_fdi_inflows_mxn new_foreign_businesses
##  Min.   :-37081      Min.   :-10.52          Min.   : 1.000        
##  1st Qu.: 33164      1st Qu.: 10.41          1st Qu.: 5.000        
##  Median : 46617      Median : 10.75          Median : 8.000        
##  Mean   : 51775      Mean   : 10.10          Mean   : 8.145        
##  3rd Qu.: 65069      3rd Qu.: 11.08          3rd Qu.:11.000        
##  Max.   :237466      Max.   : 12.38          Max.   :21.000
dataf=df

data2 <- df %>% select(Year, Quarter, New_FDI_Inflows)
data2$Fecha <- as.Date(paste(data2$Year, data2$Quarter), format = "%Y %B")

time_serie <- ts(data2$New_FDI_Inflows, start = c(2006, 1), frequency = 4)

print(time_serie)
##          Qtr1     Qtr2     Qtr3     Qtr4
## 2006   896.56  2110.38  1284.01  2677.70
## 2007  3108.22  2560.70  6059.17  6298.70
## 2008  2502.17  1915.81  4039.98  4595.51
## 2009  2984.47  2254.08  1056.01  4713.82
## 2010  2947.54  6678.89  2259.95  3749.87
## 2011  3058.29  2091.13  2604.85  1944.86
## 2012  1493.80  2111.70  2401.90 -1691.33
## 2013   749.06 15444.59   262.28  5582.68
## 2014  2427.14 -2433.24   441.89  5326.99
## 2015  4406.85  2816.75  4501.10  1724.29
## 2016  3850.77  1460.80  1550.18  4129.80
## 2017  2780.67  3134.15  3570.25  2454.70
## 2018  1934.09  2292.64  4226.74  2869.82
## 2019  2584.06  2406.22  4959.36  3579.50
## 2020  2603.81   799.40  1606.59  1731.87
## 2021  2250.76  3657.32  4149.31  3607.11
## 2022  8823.96  3664.91  2653.16  2817.87
## 2023   931.69

Se convirtió la variable de Año en el formato adecuado de fecha.

plot(time_serie, main = "IED quarter", xlab = "Year quarter", ylab = "IED")

Podemos ver que el gráfico presenta un claro componente de estacionalidad y puede haber cierta estacionariedad, sin embargo, se ve una tendencia ascendente a lo largo de toda la serie de tiempo, por lo que es necesario aplicar diversas pruebas para comprender mejor nuestra serie de tiempo.

descompose<-decompose(time_serie)
plot(descompose)

En el gráfico anterior podemos observar una ligera tendencia en toda la serie temporal como se describió anteriormente, esto podría afectar la presencia de estacionariedad. Por otro lado, se evidencia el componente estacional, que aumenta en algunos trimestres de cada período. Esto se puede explicar en el contexto de la variable dependiente con estacionalidades en la demanda de bienes y servicios, eventos económicos como ferias comerciales o temporadas de impuestos. , o incluso patrones estacionales en la disponibilidad de recursos naturales.

Todo esto hace que en algunas partes de cada año la IED aumente y disminuya periódicamente. Respecto al componente aleatorio residual, se observa cierto ruido en las series temporales, especialmente en el período 2013-2015 y 2020 a 2022. Esto se debe a variaciones en la serie temporal que no pueden explicarse con componentes de estacionalidad o tendencias en la serie temporal. Esto, en un contexto real, se puede explicar con fenómenos con las reformas constitucionales del presidente Enrique Peña Nieto en 2013 y la pandemia de COVID-19 a partir de 2020.

# The stationarity of the series is checked with the following ADF test.
adf.test(time_serie)
## 
##  Augmented Dickey-Fuller Test
## 
## data:  time_serie
## Dickey-Fuller = -5.631, Lag order = 4, p-value = 0.01
## alternative hypothesis: stationary

El resultado de la Prueba Aumentada de Dickey-Fuller (ADF) con un valor p de 0.01 (menor a 0.05) indica que la serie temporal “time_series” es estacionaria, lo que significa que no muestra tendencias en el tiempo.

acf(time_serie,main="Significant Autocorrelations") 

Podemos observar que la serie no muestra de autocorrelación serial, ya que en los periodos la función de autocorrelación no excede las líneas de significancia.

Modelo Arma Calculado

summary(arma<-arma(diff(time_serie)),order=c(1,1))
## 
## Call:
## arma(x = diff(time_serie))
## 
## Model:
## ARMA(1,1)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -4043.9  -454.3   152.0  1327.9 12087.5 
## 
## Coefficient(s):
##            Estimate  Std. Error  t value Pr(>|t|)
## ar1          0.1571          NA       NA       NA
## ma1         -1.1888          NA       NA       NA
## intercept  109.8050          NA       NA       NA
## 
## Fit:
## sigma^2 estimated as 4774485,  Conditional Sum-of-Squares = 330433746,  AIC = 1244.73
plot(arma)

Estos coeficientes indican una correlación positiva débil con el valor anterior y una correlación negativa fuerte con el error en el período anterior, respectivamente. Además, se ha incluido un término de interceptación con un valor estimado de 109.8050

Los residuos del modelo tienen una varianza estimada (sigma^2) de 4774485 y los resultados del ajuste muestran un AIC muy alto.

Modelo Arima con Log y Diff Calculado

summary(arima<-Arima(diff(log((time_serie))),order=c(1,1,1))) 
## Series: diff(log((time_serie))) 
## ARIMA(1,1,1) 
## 
## Coefficients:
##           ar1      ma1
##       -0.6977  -1.0000
## s.e.   0.0904   0.0481
## 
## sigma^2 = 0.5655:  log likelihood = -73.89
## AIC=153.78   AICc=154.17   BIC=160.4
## 
## Training set error measures:
##                       ME      RMSE       MAE      MPE     MAPE      MASE
## Training set -0.05654218 0.7341827 0.5578686 71.55558 166.8534 0.7016035
##                     ACF1
## Training set -0.02718879
plot(arima)

El coeficiente autorregresivo (AR1) es -0,6977 y el coeficiente de media móvil (MA1) es -1,0000. Estos coeficientes indican que el valor actual de la serie temporal logarítmicamente diferenciada está correlacionado negativamente con su valor anterior y con el error en el período anterior.

La varianza estimada del modelo (sigma^2) es 0,0.5655. El valor logarítmico de verosimilitud es -73.89, y los criterios de información, como el AIC (Akaike Information Criterion), el AIC corregido (AICc) y el BIC (Bayesian Information Criterion), indican que este modelo podría ser apropiado para la serie temporal.

Pruebas de Diagnostico en la Data

Modelo Arma

arma_residuals<-arma$residuals
Box.test(arma_residuals,lag=1,type="Ljung-Box")
## 
##  Box-Ljung test
## 
## data:  arma_residuals
## X-squared = 3.2686, df = 1, p-value = 0.07062

El valor de p obtenido en la prueba de Box-Ljung (0,07) es mayor que el valor de p máximo comúnmente utilizado que es 0,05. Esto significa que no se encontró evidencia significativa de autocorrelación en los residuos, ya que el valor p es mayor que 0,05, lo que respalda la validez del modelo en términos de autocorrelación.

#Testing residuals
suppressWarnings({
arma$residuals <- na.omit(arma$residuals)
adf.test(arma$residuals)
})
## 
##  Augmented Dickey-Fuller Test
## 
## data:  arma$residuals
## Dickey-Fuller = -6.32, Lag order = 4, p-value = 0.01
## alternative hypothesis: stationary

El valor de p de 0,01, inferior al umbral de 0,05, indica una fuerte evidencia contra la hipótesis nula de no estacionariedad. Esto significa que es poco probable que los residuos sean no estacionarios.

hist(arma$residuals)

Se aprecia relativa normalidad en los residuales.

Modelo Arima

arima_residuals<-arima$residuals
Box.test(arima_residuals,lag=1,type="Ljung-Box")
## 
##  Box-Ljung test
## 
## data:  arima_residuals
## X-squared = 0.049564, df = 1, p-value = 0.8238

El valor de p obtenido en la prueba de Box-Ljung (0,8) es mayor que el valor de p máximo comúnmente utilizado que es 0,05. Esto significa que no se encontró evidencia significativa de autocorrelación en los residuos, ya que el valor p es mayor que 0,05, lo que respalda la validez del modelo en términos de autocorrelación.

residuals_ts <- arima$residuals

# Interpolar los valores NA
residuals_clean <- na.approx(residuals_ts)

suppressWarnings({
  adf_test_result <- adf.test(residuals_clean)
})

# Ver el resultado
print(adf_test_result)
## 
##  Augmented Dickey-Fuller Test
## 
## data:  residuals_clean
## Dickey-Fuller = -2.9227, Lag order = 4, p-value = 0.2004
## alternative hypothesis: stationary

El valor de p de 0,01, inferior al umbral de 0,05, indica una fuerte evidencia contra la hipótesis nula de no estacionariedad. Esto significa que es poco probable que los residuos sean no estacionarios.

hist(arima$residuals)

Se aprecia normalidad en los residuales del modelo 2.

Debido a métricas como el AIC y a las pruebas de diagnóstico, el modelo 2 es elegido como el más apropiado.

Forecast de Nearshoring

suppressWarnings({
arima_restauracion<-exp(arima$fitted) # The variables are transformed back to the originals (if log is applied, the exponential must be applied (it is the opposite))
vector2 =c(arima_restauracion) #reverting "log" operation using "exp"
original2 <-c(time_serie) #Converting into a vector.
restauracion2 = vector2+original2 #reverting "diff" operation summing the original values to the differences.
ts2 <- ts(restauracion2, start = 1, end = length(restauracion2), frequency = 4) #Make time series
})
# Forecast (ARIMA)
arima_forecast<-forecast(ts2,h=5)
arima_forecast
##       Point Forecast     Lo 80    Hi 80     Lo 95    Hi 95
## 24 Q4       3036.064 1121.9856 4950.143 108.73368 5963.394
## 25 Q1       3742.547 1383.0682 6102.026 134.03557 7351.058
## 25 Q2       2318.412  856.7754 3780.049  83.03154 4553.793
## 25 Q3       3128.604 1156.1840 5101.025 112.04764 6145.161
## 25 Q4       3036.064 1121.9853 4950.143 108.73322 5963.395
plot(arima_forecast)

autoplot(arima_forecast)

En el pronóstico realizado para la Inversión Extranjera Directa (IED) relacionada con el fenómeno del nearshoring, se observan tendencias y variaciones interesantes para los próximos cinco trimestres. La predicción se presenta con intervalos de confianza del 80% y del 95%, lo que nos permite entender la incertidumbre asociada con cada estimación de punto.

Para el cuarto trimestre del año 24, el pronóstico de punto estima una IED de 3,036.064 millones de dólares. Los intervalos de confianza sugieren que, con un 80% de confianza, la IED podría variar entre 1,121.986 y 4,950.143 millones de dólares. Ampliando la certeza al 95%, el rango se extiende desde 108.734 hasta 5,963.394 millones de dólares, indicando una mayor incertidumbre en las estimaciones.

En el primer trimestre del año 25, se espera un aumento en la IED hasta los 3,742.547 millones de dólares. El intervalo de confianza del 80% se sitúa entre 1,383.068 y 6,102.026 millones de dólares, mientras que el intervalo al 95% se amplía desde 134.036 hasta 7,351.058 millones de dólares, reflejando nuevamente la incertidumbre en el pronóstico.

Para el segundo trimestre del año 25, el pronóstico muestra una disminución en la IED a 2,318.412 millones de dólares. Los intervalos de confianza para este trimestre son más estrechos, con el intervalo del 80% variando entre 856.775 y 3,780.049 millones de dólares, y el del 95% entre 83.032 y 4,553.793 millones de dólares.

En el tercer trimestre del año 25, se prevé un repunte en la IED a 3,128.604 millones de dólares, con intervalos de confianza similares a los observados en el cuarto trimestre del año 24.

Finalmente, para el cuarto trimestre del año 25, el pronóstico vuelve a estimar una IED de 3,036.064 millones de dólares, con intervalos de confianza prácticamente idénticos a los del cuarto trimestre del año 24.

Este análisis de pronóstico muestra una variabilidad significativa en la IED esperada relacionada con el nearshoring a lo largo de los próximos cinco trimestres.

Pronosticar el desempeño de FORM

Bases de Datos de Ventas

#file.choose()
setwd("../databases/")
ventas1 <- read_excel("form/FORM-Ventas.xlsx")
ventas2 <- read_excel("form/FORM-Ventas.xlsx")

# data de bases
names(ventas1)
## [1] "Mes"              "Año"              "Total Carton"     "Total Retornable"
## [5] "Servicios"        "Muestras"         "Variación"        "Ventas Totales"
str(ventas1)
## tibble [72 × 8] (S3: tbl_df/tbl/data.frame)
##  $ Mes             : chr [1:72] "Enero" "Febrero" "Marzo" "Abril" ...
##  $ Año             : num [1:72] 2017 2017 2017 2017 2017 ...
##  $ Total Carton    : num [1:72] NA NA NA NA NA NA NA NA NA NA ...
##  $ Total Retornable: num [1:72] NA NA NA NA NA NA NA NA NA NA ...
##  $ Servicios       : num [1:72] NA NA NA NA NA NA NA NA NA NA ...
##  $ Muestras        : num [1:72] NA NA NA NA NA NA NA NA NA NA ...
##  $ Variación       : num [1:72] NA NA NA NA NA NA NA NA NA NA ...
##  $ Ventas Totales  : num [1:72] 5166155 5166155 5166155 5166155 5166155 ...

Analisis de Numero de Data Faltante

# Calcula y muestra la cantidad de valores NA por columna en ventas1.
na_count1 <- colSums(is.na(ventas1))
na_count1
##              Mes              Año     Total Carton Total Retornable 
##                0                0               51               51 
##        Servicios         Muestras        Variación   Ventas Totales 
##               51               63               63                0
# Elimina columnas con NA en ventas1 y las últimas 3 filas.
ventas1 <- ventas1[, colSums(is.na(ventas1)) == 0]
ventas1 <- head(ventas1, -3)

# Calcula y muestra la cantidad de valores NA por columna en ventas2.
na_count2 <- colSums(is.na(ventas2))
na_count2
##              Mes              Año     Total Carton Total Retornable 
##                0                0               51               51 
##        Servicios         Muestras        Variación   Ventas Totales 
##               51               63               63                0
# Elimina filas con NA en ventas2.
ventas2 <- ventas2[complete.cases(ventas2), ]

# Renombra la columna "Ventas Totales" a "Ventas_totales" en ventas1.
names(ventas1)[names(ventas1) == "Ventas Totales"] <- "Ventas_totales"

Observamos una presencia significativa de valores NA. Por ello, decidimos eliminar las columnas que contengan valores NA en la base de datos 1 y las filas con valores NA en la base de datos 2.

#ventas1$Mes <- as.yearmon(paste(ventas1$Año, ventas1$Mes), "%Y %B")
#ventas2$Mes <- as.yearmon(paste(ventas2$Año, ventas2$Mes), "%Y %B")

Pruebas de Diagnostico en la Data

ventas1$Mes <- as.Date(paste(ventas1$Año, ventas1$Mes), format = "%Y %B")

Ventas <- ts(ventas1$Ventas_totales, start = c(2017, 1), end=c(2022,9), frequency = 12)

print(Ventas)
##           Jan      Feb      Mar      Apr      May      Jun      Jul      Aug
## 2017  5166155  5166155  5166155  5166155  5166155  5166155  5166155  5166155
## 2018  7248220  7248220  7248220  7248220  7248220  7248220  7248220  7248220
## 2019  6786917  6786917  6786917  6786917  6786917  6786917  6786917  6786917
## 2020  6059791  6643181  8368674  4925778  2235669  7842003  5599913  8883507
## 2021  9294478 11179236 10360017  7872345  9219847  5407600  7936029  4773524
## 2022  7534073  7898590 10597117  8397928  7786912  8623444  9495207 11053017
##           Sep      Oct      Nov      Dec
## 2017  5166155  5166155  5166155  5166155
## 2018  7248220  7248220  7248220  7248220
## 2019  6786917  6786917  6786917  6786917
## 2020  7452457  8078683  7539929 12285123
## 2021  6358278  5123874  5913523  6500150
## 2022 11577528

La variable dependiente se define como “Ventas Totales”, correspondiente a las ventas totales realizadas por FORM.

ts_plot(Ventas)

Entre 2018 y 2020, la serie de tiempo muestra una tendencia lineal. Sin embargo, después de 2020, emerge un patrón estacional claro, y aunque puede presentar cierta estacionariedad, se observa una tendencia ascendente general a lo largo de todo el periodo analizado.

Ventasdesc<-decompose(Ventas)
plot(Ventasdesc)

La tendencia, que representa el componente a largo plazo de la serie de tiempo, indica un aumento constante en las ventas totales de FORM a lo largo del periodo observado.

La estacionalidad, por otro lado, refleja las variaciones a corto plazo, revelando que las ventas de FORM tienden a incrementarse en determinadas épocas del año, como el último trimestre, y disminuir en otras, como el primer trimestre, lo cual podría estar relacionado con el aumento progresivo en la demanda de los clientes a medida que avanza el año, seguido de una caída hacia el final.

La aleatoriedad, el componente impredecible de la serie de tiempo, indica fluctuaciones en los datos que no se explican por la tendencia ni por la estacionalidad, sugiriendo incrementos inesperados en la demanda por parte de los clientes.

adf.test(ventas1$Ventas_totales)
## 
##  Augmented Dickey-Fuller Test
## 
## data:  ventas1$Ventas_totales
## Dickey-Fuller = -2.7165, Lag order = 4, p-value = 0.284
## alternative hypothesis: stationary

Dado que el valor p de 0.284 supera el umbral de significancia comúnmente aceptado de 0.05, no contamos con suficiente evidencia para descartar la hipótesis nula, que asume la no estacionariedad de la serie de tiempo. Por ende, de acuerdo con este análisis, la serie temporal se considera no estacionaria.

acf(ventas1$Ventas_totales)

El gráfico indica que la Función de Autocorrelación (ACF) es positiva para los rezagos 1, 2 y 3, lo que sugiere una correlación positiva entre los valores de la serie temporal en estos intervalos. Esto implica que los valores de la serie tienden a moverse en la misma dirección en estos periodos.

Por otro lado, la ACF es negativa para los rezagos 4, 5 y 6, señalando una correlación negativa en estos puntos. Esto significa que los valores de la serie temporal tienden a moverse en direcciones opuestas durante estos intervalos.

Estas características sugieren que la serie temporal podría exhibir un comportamiento estacional, donde la correlación positiva a corto plazo indica patrones de movimiento conjunto debido a tendencias estacionales, como períodos de alta o baja demanda durante ciertas épocas del año. La correlación negativa a más largo plazo podría indicar una tendencia de los valores de la serie a retornar hacia un promedio a lo largo del tiempo, reflejando una reversión a la media estacional.

Modelo Arma Calculado

summary(ARMA<-arma(diff(Ventas)),order=c(1,1))
## 
## Call:
## arma(x = diff(Ventas))
## 
## Model:
## ARMA(1,1)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -4683342  -153905  -146579   202842  4318165 
## 
## Coefficient(s):
##             Estimate  Std. Error  t value Pr(>|t|)  
## ar1       -4.971e-01   2.035e-01   -2.443   0.0146 *
## ma1       -5.459e-02   2.396e-01   -0.228   0.8198  
## intercept  1.386e+05         NaN      NaN      NaN  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Fit:
## sigma^2 estimated as 1.882e+12,  Conditional Sum-of-Squares = 1.242001e+14,  AIC = 2120.88
plot(ARMA)

El término AR(1) es significativo (p-value = 0.0146), lo que indica que es importante en el modelo. Sin embargo, el término MA(1) no es significativo (p-value = 0.8199). Los residuos del modelo tienen una varianza estimada (sigma^2) de 1.882e+12 y los resultados del ajuste muestran un AIC de 2120.88. Además, se ha incluido un término de interceptación con un valor estimado de 1.386e+05

Modelo Arima Calculado

summary(ARIMA<-Arima(diff(log((Ventas))),order=c(1,1,1))) 
## Series: diff(log((Ventas))) 
## ARIMA(1,1,1) 
## 
## Coefficients:
##           ar1      ma1
##       -0.4977  -1.0000
## s.e.   0.1040   0.0422
## 
## sigma^2 = 0.05168:  log likelihood = 2.55
## AIC=0.91   AICc=1.29   BIC=7.52
## 
## Training set error measures:
##                       ME      RMSE       MAE MPE MAPE      MASE        ACF1
## Training set 0.004611339 0.2222576 0.1163891 NaN  Inf 0.4462246 -0.06226768
plot(ARIMA)

Los coeficientes estimados para el término AR(1) y el término MA(1) son -0.4977 y -1.0000 respectivamente. Esto indica que hay una relación negativa entre el valor actual y los valores rezagados.

Los errores estándar de los coeficientes (s.e.) son 0.1040 y 0.0422 para el término AR(1) y el término MA(1) respectivamente.

La varianza estimada de los errores del modelo (sigma^2) es de aproximadamente 0.05168.

El logaritmo de la verosimilitud es de aproximadamente 2.55 y el AIC es de 0.91. Estas medidas proporcionan información sobre la calidad del ajuste del modelo, con valores más bajos indicando un mejor ajuste.

La serie de tiempo de las ventas no es estacionaria, lo que significa que la media y la varianza de la serie de tiempo están cambiando con el tiempo.

Evaluación de Modelos

ARMA

arma_residuals<-ARMA$residuals
Box.test(arma_residuals,lag=1,type="Ljung-Box")
## 
##  Box-Ljung test
## 
## data:  arma_residuals
## X-squared = 3.1682e-05, df = 1, p-value = 0.9955

Esto significa que no se encontró evidencia significativa de autocorrelación en los residuos.

suppressWarnings({
ARMA$residuals <- na.omit(ARMA$residuals)
adf.test(ARMA$residuals)
})
## 
##  Augmented Dickey-Fuller Test
## 
## data:  ARMA$residuals
## Dickey-Fuller = -3.231, Lag order = 4, p-value = 0.09034
## alternative hypothesis: stationary

Dado que el valor p (0.09034) es mayor que el nivel de significancia comúnmente utilizado de 0.05, no podemos afirmar con confianza que los residuos sean estacionarios según esta prueba.

hist(ARIMA$residuals)

La normalidad se ve en los residuales.

ARIMA

arima_residuals<-ARIMA$residuals
Box.test(arima_residuals,lag=1,type="Ljung-Box")
## 
##  Box-Ljung test
## 
## data:  arima_residuals
## X-squared = 0.27546, df = 1, p-value = 0.5997

Esto significa que no se encontró evidencia significativa de autocorrelación en los residuos.

suppressWarnings({
ARIMA$residuals <- na.omit(ARIMA$residuals)
adf.test(ARIMA$residuals)
})
## 
##  Augmented Dickey-Fuller Test
## 
## data:  ARIMA$residuals
## Dickey-Fuller = -3.6993, Lag order = 4, p-value = 0.03156
## alternative hypothesis: stationary

Dado que el valor p (0.03156) es menor que el nivel de significancia comúnmente utilizado de 0.05, los residuos parecen ser estacionarios según esta prueba.

hist(ARIMA$residuals)

La normalidad se ve en los residuales.

Selección de Modelo

Se selecciono el modelo ARIMA, ya que tiene el AIC mas bajo en comparación con el modelo ARMA.

Forecast de Ventas de FORM

suppressWarnings({
  # Asigna las predicciones ajustadas por el modelo ARIMA a la variable.
  arima_restauracion <- (ARIMA$fitted)
  
  # Convierte las predicciones ajustadas en un vector.
  vector2 <- c(arima_restauracion)
  
  # Convierte los datos originales de ventas en un vector.
  original2 <- c(Ventas)
  
  # Realiza la operación inversa a la diferencia, sumando los valores originales a las diferencias.
  restauracion2 <- vector2 + original2
  
  # Convierte el vector restaurado en una serie temporal, especificando inicio, fin y frecuencia.
  ts2 <- ts(restauracion2, start = 1, end = length(restauracion2), frequency = 12)
})
arima_forecast<-forecast(ts2,h=5)
arima_forecast
##        Point Forecast   Lo 80   Hi 80   Lo 95    Hi 95
## Feb 69        5842742 4269322 7416162 3436403  8249081
## Mar 69        6439323 4550657 8327989 3550858  9327788
## Apr 69        5807800 3886135 7729466 2868867  8746734
## May 69        5986388 3885645 8087132 2773578  9199199
## Jun 69        6553629 4200423 8906835 2954712 10152546
plot(arima_forecast)

autoplot(arima_forecast)

Forecast Calculado

Los pronósticos para los próximos periodos se presentan a continuación, reflejando las expectativas de ventas futuras basadas en el análisis realizado:

  • Periodo 1: 5,842,742
  • Periodo 2: 6,439,323
  • Periodo 3: 5,807,800
  • Periodo 4: 5,986,388
  • Periodo 5: 6,553,629

Cada valor representa la proyección de ventas para el periodo correspondiente, indicando fluctuaciones en la demanda o en las tendencias de ventas identificadas por el modelo. Estos pronósticos son cruciales para la planificación estratégica y la toma de decisiones en el ámbito empresarial.

Modelo Var Calculado

Del conjunto de datos, se seleccionaron las variables explicativas que podrían explicar las ventas de FORM.

setwd("../databases/")
ventas2 <- read_excel("form/FORM-Ventas.xlsx")

names(ventas2)[names(ventas2) == "Ventas Totales"] <- "Ventas_totales"
names(ventas2)[names(ventas2) == "Total Carton"] <- "Total_carton"
names(ventas2)[names(ventas2) == "Total Retornable"] <- "Total_retornable"
names(ventas2)[names(ventas2) == "Variación"] <- "Variacion"

Impacto de Variables sobre Ventas

Sys.setlocale("LC_TIME", "es_ES.UTF-8")
## [1] "es_ES.UTF-8"
ventas2 <- na.omit(ventas2[, c("Año", "Mes", "Ventas_totales", "Total_carton", "Total_retornable", "Variacion", "Servicios", "Muestras")])
ventas2$Fecha <- as.Date(paste(ventas2$Año, ventas2$Mes, "01"), format = "%Y %B %d")
Ventas2 <- ts(ventas2$Ventas_totales, start = c(as.numeric(format(min(ventas2$Fecha), "%Y")), as.numeric(format(min(ventas2$Fecha), "%m"))), frequency = 12)
plot(Ventas2)

Carton <- ts(ventas2$Total_carton, start = c(year(min(ventas2$Fecha)), month(min(ventas2$Fecha))), frequency = 12)

ts_plot(Carton)
Retornable <- ts(ventas2$Total_retornable, start = c(year(min(ventas2$Fecha)), month(min(ventas2$Fecha))), frequency = 12)
ts_plot(Retornable)
servicio <- ts(ventas2$Servicios, start = c(year(min(ventas2$Fecha)), month(min(ventas2$Fecha))), frequency = 12)
ts_plot(servicio)
muestra <- ts(ventas2$Muestras, start = c(year(min(ventas2$Fecha)), month(min(ventas2$Fecha))), frequency = 12)
ts_plot(muestra)
variacion <- ts(ventas2$Variacion, start = c(year(min(ventas2$Fecha)), month(min(ventas2$Fecha))), frequency = 12)
ts_plot(variacion)

Total cartón: al igual que la variable dependiente, muestra una tendencia de crecimiento, esto puede significar que estan altamente relacionadas.

Total retornable: al igual que la variable dependiente, muestra una tendencia de crecimiento, esto puede significar que estan altamente relacionadas.

Serivicos: La serie temporal no muestra una relación clara entre los servicios y las ventas, esto puede ser debido a la demanda del mercado.

Tests de Diagnostico

adf.test(Carton) 
## 
##  Augmented Dickey-Fuller Test
## 
## data:  Carton
## Dickey-Fuller = -0.6872, Lag order = 2, p-value = 0.9594
## alternative hypothesis: stationary

Dado que el valor p (0.9594) es mucho mayor que el nivel de significancia comúnmente utilizado de 0.05, o podemos afirmar con confianza que la serie “Carton” sea estacionaria según esta prueba.

adf.test(Retornable) 
## 
##  Augmented Dickey-Fuller Test
## 
## data:  Retornable
## Dickey-Fuller = -1.3311, Lag order = 2, p-value = 0.8272
## alternative hypothesis: stationary

Dado que el valor p (0.8272) es mucho mayor que el nivel de significancia comúnmente utilizado de 0.05, o podemos afirmar con confianza que la serie “Carton” sea estacionaria según esta prueba.

Evaluación de Modelos Var

var_ts<-cbind(diff(log(Ventas2)), diff(log(Carton)), diff(log(Retornable)))
colnames(var_ts)<-cbind("Ventas_2", "Carton", "Retornable") 
acf_var_ts <- lapply(var_ts, acf)

head(var_ts)
##             Ventas_2     Carton Retornable
## Feb 2022  0.04724851  0.1841863 -0.6135258
## Mar 2022  0.29389769  0.1113557  1.1143465
## Apr 2022 -0.23259698 -0.0999837 -1.0579750
## May 2022 -0.07554059 -0.1447440  0.3906362
## Jun 2022  0.10204007  0.2323875 -0.4549069
## Jul 2022  0.09630262 -0.1789962  1.0948009
var_ts <- ts(var_ts, frequency = 1, start = c(2022))

# Realiza la selección de rezagos
lag_selection <- VARselect(var_ts,lag.max=3,type="const", season=12)

# Imprime los resultados
lag_selection$selection
## AIC(n)  HQ(n)  SC(n) FPE(n) 
##      1      1      1      1
lag_selection$criteria
##           1    2    3
## AIC(n) -Inf -Inf -Inf
## HQ(n)  -Inf -Inf -Inf
## SC(n)  -Inf -Inf -Inf
## FPE(n)    0    0    0
var_ts
## Time Series:
## Start = 2022 
## End = 2029 
## Frequency = 1 
##         Ventas_2     Carton Retornable
## 2022  0.04724851  0.1841863 -0.6135258
## 2023  0.29389769  0.1113557  1.1143465
## 2024 -0.23259698 -0.0999837 -1.0579750
## 2025 -0.07554059 -0.1447440  0.3906362
## 2026  0.10204007  0.2323875 -0.4549069
## 2027  0.09630262 -0.1789962  1.0948009
## 2028  0.15191627  0.3432633 -1.3816387
## 2029  0.04636259 -0.1319051  1.5359121

Restricciones de Modelo Var

var_modelo<-VAR(var_ts,p=1) 
#summary(VAR_ev2model1)
matriz_correlacion <- cor(var_ts)
# Imprimir la matriz de correlación
print(matriz_correlacion)
##             Ventas_2     Carton Retornable
## Ventas_2   1.0000000  0.5037499  0.3336449
## Carton     0.5037499  1.0000000 -0.6041826
## Retornable 0.3336449 -0.6041826  1.0000000

No es posible aplicar el modelo VAR debido a la alta correlación entre las variables explicativas y la variable dependiente. Este fenómeno podría explicarse por el hecho de que el total de cartón y el total de retornable constituyen conjuntamente el total de ventas. La matriz de correlación revela lo siguiente:

  • La correlación entre Ventas_2 y Carton es aproximadamente 0.5037. Esto sugiere una correlación positiva moderada entre estas dos variables.
  • La correlación entre Ventas_2 y Retornable es aproximadamente 0.3336. Esto también indica una correlación positiva, pero más débil en comparación con la correlación entre Ventas_2 y Carton.
modelo <- lm(Ventas_totales ~ Total_carton + Total_retornable + servicio + muestra + variacion, data = ventas2)
durbinWatsonTest(modelo)
##  lag Autocorrelation D-W Statistic p-value
##    1       0.2217584      1.061769       0
##  Alternative hypothesis: rho != 0

Según el test de Durbin-Watson, no hay evidencia de autocorrelación de primer orden en los residuos del modelo de regresión lineal.

var_residuals<-data.frame(residuals(var_modelo))

forecast_2<-predict(var_modelo,n.ahead=5,ci=0.95) ### forecast for the next 12 months
fanchart(forecast_2,names="Ventas",main="Ventas",xlab="Time Period",ylab="Ventas")

forecast_2
## $Ventas_2
##            fcst      lower     upper        CI
## [1,] 0.06664341 -0.3821737 0.5154605 0.4488171
## [2,] 0.03512111 -0.4255364 0.4957786 0.4606575
## [3,] 0.07128064 -0.3925222 0.5350835 0.4638028
## [4,] 0.03611558 -0.4289356 0.5011667 0.4650511
## [5,] 0.06683582 -0.3984906 0.5321622 0.4653264
## 
## $Carton
##             fcst      lower     upper        CI
## [1,]  0.16278859 -0.2454587 0.5710359 0.4082473
## [2,] -0.04597671 -0.4960796 0.4041261 0.4501029
## [3,]  0.09099331 -0.3889659 0.5709526 0.4799592
## [4,]  0.01054197 -0.4945303 0.5156143 0.5050723
## [5,]  0.04942303 -0.4742693 0.5731153 0.5236923
## 
## $Retornable
##             fcst      lower      upper        CI
## [1,] -1.11951654 -1.6385358 -0.6004972 0.5190193
## [2,]  0.81272223 -0.2119736  1.8374181 1.0246959
## [3,] -0.48314477 -2.1151728  1.1488833 1.6320281
## [4,]  0.29935152 -1.8127393  2.4114423 2.1120908
## [5,] -0.09891405 -2.5412956  2.3434675 2.4423815
forecast_2$fcst$Ventas_2 <- exp(forecast_2$fcst$Ventas_2)  


forecast_2$fcst$Ventas_2[1] = forecast_2$fcst$Ventas_2[1] + tail(ventas2$Ventas_totales, 1)
forecast_2$fcst$Ventas_2[2] = forecast_2$fcst$Ventas_2[2] + tail(ventas2$Ventas_totales, 1)
forecast_2$fcst$Ventas_2[3] = forecast_2$fcst$Ventas_2[3] + tail(ventas2$Ventas_totales, 2)
forecast_2$fcst$Ventas_2[4] = forecast_2$fcst$Ventas_2[4] + tail(ventas2$Ventas_totales, 3)
forecast_2$fcst$Ventas_2[5] = forecast_2$fcst$Ventas_2[5] + tail(ventas2$Ventas_totales, 4)
forecast_2$fcst$Ventas_2
##          fcst     lower    upper       CI
## [1,] 11577529 0.6823765 1.674409 1.566458
## [2,] 11577529 0.6534192 1.641776 1.585116
## [3,] 11053018 0.6753514 1.707591 1.590109
## [4,]  9495208 0.6512019 1.650646 1.592096
## [5,]  8623445 0.6713326 1.702610 1.592534

Forecast de Ventas para Modelo VAR

Presentamos a continuación las proyecciones de ventas utilizando el modelo VAR para los próximos cinco periodos. Estas estimaciones nos permiten anticipar la dinámica del mercado y ajustar nuestras estrategias operativas y financieras acorde a las expectativas futuras:

  • Periodo 1: Se espera que las ventas alcancen los 11,577,529, manteniendo una línea con los resultados anteriores.
  • Periodo 2: Las ventas se proyectan estables, sin variación respecto al periodo anterior, en 11,577,529.
  • Periodo 3: Se anticipa una leve disminución en las ventas, situándose en 11,053,018, lo que podría reflejar ajustes estacionales o de mercado.
  • Periodo 4: Se prevé una reducción más notable en las ventas, descendiendo a 9,495,208. Este periodo requerirá atención para mitigar los impactos negativos.
  • Periodo 5: Las ventas podrían disminuir hasta los 8,623,445, indicando la importancia de desarrollar estrategias de recuperación y adaptación.

Estas proyecciones son una herramienta vital para la planificación estratégica, permitiéndonos preparar con anticipación para los cambios en el entorno de ventas.

Insights de Ambos Modelos

Los pronósticos para las ventas en los próximos cinco períodos revelan tendencias y desafíos importantes para el futuro próximo. Al inicio, se espera que las ventas se mantengan estables, alcanzando una cifra proyectada de alrededor de 11,577,529 en el primer período. Esta estabilidad sugiere una fase de mercado sin grandes cambios, ofreciendo una oportunidad para consolidar estrategias actuales.

Para el segundo período, las proyecciones indican una continuidad en esta tendencia, con ventas esperadas similares a las del primer período. Esta persistencia subraya una etapa de estabilidad, posiblemente debido a la efectividad de las estrategias de mercado actuales o a un equilibrio en la dinámica de demanda y oferta.

No obstante, el escenario se modifica ligeramente en el tercer período, donde se prevé un descenso en las ventas hasta 11,053,018. Este ligero retroceso podría ser un indicativo de una disminución en la demanda o de la influencia de factores externos que afectan negativamente el volumen de ventas.

El cuarto período presenta retos más significativos, con una proyección de ventas que disminuye considerablemente a 9,495,208. Este notable declive señala la necesidad de revisar críticamente las estrategias de mercado y, posiblemente, adaptarse a un entorno competitivo más agresivo o a cambios en las preferencias de los consumidores.

Finalmente, el quinto período continúa con esta tendencia de decrecimiento, evidenciando una reducción adicional en las ventas. Este patrón sugiere un aumento en la competencia o una significativa disminución en la demanda, destacando la importancia de una estrategia empresarial flexible y proactiva para superar estos desafíos y fomentar un crecimiento renovado.

Estos pronósticos no solo proporcionan una visión de los posibles escenarios futuros, sino que también enfatizan la necesidad de adaptabilidad y proactividad en la planificación estratégica para mantener la relevancia y competitividad en un mercado dinámico.

Diseño, Organización, y Limpieza de Base de Datos

Selección de Información

Seleccionar información y datos que consideren relevantes para responder las preguntas de análisis.

** Base de Datos Maestra para Situación Problema 1**

Dado que la primera situación problema tiene un enfoque con base interna, es necesario utilizar las bases de datos relacionadas al area de capital humano para resolver este problema. Dado que hasta la fecha actual la empresa FORM unicamente ha proporcionado 2 bases de datos relacionadas a dicha problematica, actualmente solo se limpiaron y unificaron esas bases dividiendose en 2 bases maestras actualmente, FORM_Bajas y FORM_Satisfaccion, cada una teniendo un enfoque distinto. Además de esto, se descargo la base de datos official proporcionada por parte del Govierno de Mexico y de libre uso que incluye los poligonos para llevar a cabo un analisis espacial. De esta forma e integrando esta ultima base de datos, podríamos tener ambas bases listas para la creación de un modelo de clasificación.

** Base de Datos Maestra para Situación Problema 2**

Con respecto a las problematicas asociadas a la situación problema 2, actualmente no se cuenta con la data interna suficiente como para poder crear una base maestra lista que nos permita crear un modelo util y real que permita al socio formador predecir la demanda. A pesar de esto, contamos actualmente con una base de datos ligada al fenomeno de nearshoring, una base de datos unificada para la exportación e importación de materia prima y de las industrias manufactureras relacionadas que si bien no se han unificados todas las bases en 1, ya hay una base maestra para cada campo que se puede encontrar dentro de la carpeta de databases en este mismo repositorio. Una vez con datos más especificos de producción o venta compartidos por el socio formador, sería posible realizar lo solicitado y crear una base de datos maestra que unifique tanto los factores externos como interno.

Diseño de Bases

Diseñar y organizar base(s) de datos a partir de la información y datos seleccionados.

Situación Problema 1: Enfoque en Capital Humano

Para abordar los desafíos asociados al capital humano, se propone la siguiente estructura y organización de las bases de datos:

  • Base de Datos FORM_Bajas: Esta base se enfocará en recopilar información detallada sobre las bajas de personal, incluyendo motivos de salida, fechas de baja, duración del empleo, y cualquier dato relevante que pueda influir en la decisión de dejar la empresa. Se buscará identificar patrones que puedan prevenir futuras bajas.

  • Base de Datos FORM_Satisfaccion: Contendrá resultados de encuestas de satisfacción laboral, feedback sobre el ambiente laboral, oportunidades de crecimiento, balance entre vida laboral y personal, y otros factores que afectan la satisfacción y retención del personal. Esta base se utilizará para analizar correlaciones entre satisfacción y productividad o permanencia en la empresa.

Para ambas bases, se realizará un trabajo de limpieza de datos, normalización y unificación de formatos para asegurar coherencia y facilitar el análisis. Además, se integrará la base de datos de polígonos del Gobierno de México para realizar análisis espacial, permitiendo explorar la distribución geográfica de las bajas y la satisfacción del personal, y cómo estos factores pueden influir en la dinámica de trabajo.

Situación Problema 2: Enfoque en Demanda y Nearshoring

La estructuración de la base de datos para esta situación problema se realizará de la siguiente manera:

  • Base de Datos de Nearshoring y Comercio Exterior: Incluirá datos sobre importaciones, exportaciones, tendencias de nearshoring, y cómo estos factores impactan en las industrias relevantes para la empresa. Se desglosará por tipo de producto, origen, destino, volumen y valor de las transacciones.

  • Base Maestra Integrada: A partir de los datos de nearshoring y comercio exterior, se buscará integrar esta información con datos internos de producción, ventas, y cualquier otro dato relevante proporcionado por el socio formador. Esta base maestra permitirá analizar la demanda desde una perspectiva interna y externa, facilitando la creación de modelos predictivos.

Para ambas situaciones, se adoptarán prácticas de gestión de datos que incluyen la indexación adecuada, la implementación de claves foráneas para mantener la integridad referencial, y la creación de vistas o tablas agregadas para análisis específicos. Además, se prestará especial atención a la seguridad y privacidad de los datos, asegurando que la información sensible sea manejada conforme a las normativas aplicables.

Bases Maestras

Visualizar en R los primeros 6 renglones de la nueva base de datos.

Base de Datos: Bajas FORM
setwd("../databases")
bajas <- read_xlsx("form/form-bajas.xlsx")
head(bajas)
## # A tibble: 6 × 12
##   `Motivo de Baja`      Puesto    Dpto     SD `Estado Civil` Genero   Año Estado
##   <chr>                 <chr>     <chr> <dbl> <chr>          <chr>  <dbl> <chr> 
## 1 Separacion voluntaria ayudante… stab…  181. soltero        femen…  2023 nuevo…
## 2 Separacion voluntaria ayudante… <NA>   181. casado         femen…  2023 nuevo…
## 3 Separacion voluntaria gestor    emba…  177. casado         mascu…  2023 nuevo…
## 4 Separacion voluntaria ayudante… celd…  181. soltero        femen…  2023 nuevo…
## 5 Separacion voluntaria ayudante… <NA>   181. casado         femen…  2023 nuevo…
## 6 Separacion voluntaria soldador  <NA>   181. soltero        mascu…  2023 nuevo…
## # ℹ 4 more variables: Municipio <chr>, Dias_trabajados <dbl>, Meses <dbl>,
## #   Edad <dbl>
Base de Datos: Satisfacción FORM
setwd("../databases")
satis <- read_xlsx("form/Encuesta_Datos_FORM_Fall2023.xlsx")
head(satis)
## # A tibble: 6 × 22
##   encuesta puesto      antiguedad razon_entrada salario_bueno prestaciones_bueno
##      <dbl> <chr>            <dbl> <chr>         <chr>         <chr>             
## 1        1 administra…          9 salario       Totalmente d… Medianamente de a…
## 2        2 costurera           36 otro          Medianamente… Medianamente de a…
## 3        3 ayudante g…          4 ubicacion em… Medianamente… Totalmente en des…
## 4        4 ayudante g…          2 ubicacion em… Totalmente d… Medianamente de a…
## 5        5 ayudante g…          1 ubicacion em… Ni de acuerd… Totalmente en des…
## 6        6 ayudante g…         36 razones pers… Medianamente… Totalmente de acu…
## # ℹ 16 more variables: jornada_no_excesiva <chr>,
## #   ofrecimiento_herramientas <chr>, no_molestia_temperatura <chr>,
## #   estres_bajo <chr>, facilidad_transporte <chr>, zona_trabajo_comoda <chr>,
## #   permanencia_form_futuro <chr>, sufrido_situaciones_conflicto <chr>,
## #   molestias_puesto <chr>, sentimiento_form <chr>, edad <chr>, genero <chr>,
## #   estado_civil <chr>, municipio <chr>, nivel_escolar <chr>,
## #   personas_dependientes <dbl>
Base de Datos: Nearshoring
setwd("../databases")
nearshoring <- read_xlsx("nearshoring/annual_economic_data.xlsx")
tail(nearshoring)
## # A tibble: 6 × 20
##     Año IED_Flujos_Reales Exportaciones Educacion Salario_Diario Innovacion
##   <dbl>             <dbl>         <dbl>     <dbl>          <dbl>      <dbl>
## 1  2017           683139.        33323.      9.35           88.4       14.0
## 2  2018           670908.        35342.      9.45           88.4       13.2
## 3  2019           616010.        36415.      9.58          103.        12.7
## 4  2020           514583.        41077.      8.46          123.        11.3
## 5  2021           551831.        44915.      9.58          142.        15.1
## 6  2022           555904.        46478.      7.20          173.        11.3
## # ℹ 14 more variables: Inseguridad_Robo <dbl>, Inseguridad_Homicidio <dbl>,
## #   Tipo_de_Cambio <dbl>, Densidad_Carretera <dbl>, Densidad_Poblacion <dbl>,
## #   PIB_Per_Capita <dbl>, INPC <dbl>, Empleo <dbl>, CO2_Emisiones <dbl>,
## #   Empresas_Extranjeras_Registradas <dbl>,
## #   Población_Economicamente_Activa <dbl>,
## #   Poblacion_ocupada_industria_manufacturera <dbl>, Poblacion_ocupada <dbl>,
## #   Tasa_de_ocupacion_industria_manufacturera <dbl>
Base de Datos: Exportación de Vehiculos
setwd("../databases")
export <- read_csv("industry_autos_mx/exportacion_vehiculos_mx.csv")
head(export)
## # A tibble: 6 × 7
##    year year_quarter quarter state_id State          trade_value region      
##   <dbl>        <dbl> <chr>      <dbl> <chr>                <dbl> <chr>       
## 1  2006        20061 2006-Q1        1 Aguascalientes    41467663 Centro-Norte
## 2  2006        20062 2006-Q2        1 Aguascalientes    68865388 Centro-Norte
## 3  2006        20063 2006-Q3        1 Aguascalientes    98879401 Centro-Norte
## 4  2006        20064 2006-Q4        1 Aguascalientes   172591417 Centro-Norte
## 5  2007        20071 2007-Q1        1 Aguascalientes   166572113 Centro-Norte
## 6  2007        20072 2007-Q2        1 Aguascalientes   167222076 Centro-Norte

Glosario de Variables

Elaborar glosario de las variables que se incluyen en la nueva base de datos.

Glosario de Variables

Elaboración de un glosario para las variables incluidas en las nuevas bases de datos, sin incluir el tipo de dato.

Base de Datos: Bajas FORM

  • Motivo de Baja: Razón por la cual el empleado dejó la empresa.
  • Puesto: Cargo que el empleado ocupaba en la empresa.
  • Dpto: Departamento al que pertenecía el empleado.
  • SD: Salario diario del empleado.
  • Estado Civil: Estado civil del empleado al momento de la baja.
  • Género: Género del empleado.
  • Año: Año en que se produjo la baja.
  • Estado: Estado de la república donde residía el empleado.
  • Municipio: Municipio de residencia del empleado.
  • Dias_trabajados: Total de días que el empleado trabajó en la empresa.
  • Meses: Número de meses que el empleado estuvo en la empresa.
  • Edad: Edad del empleado al momento de la baja.

Base de Datos: Satisfacción FORM

  • Encuesta: Identificador único de la encuesta de satisfacción.
  • Puesto: Cargo que ocupa el empleado dentro de la empresa.
  • Antigüedad: Tiempo (en años) que el empleado lleva trabajando en la empresa.
  • Razon_entrada: Motivo principal por el que el empleado decidió ingresar a la empresa.
  • Salario_bueno: Percepción del empleado sobre la competitividad de su salario.
  • Prestaciones_bueno: Valoración del empleado sobre las prestaciones ofrecidas por la empresa.
  • Jornada_no_excesiva: Opinión del empleado sobre la duración de su jornada laboral.
  • Ofrecimiento_herramientas: Si el empleado considera que se le proporcionan las herramientas necesarias para su trabajo.
  • No_molestia_temperatura: Confort térmico en el lugar de trabajo.
  • Estres_bajo: Percepción del empleado sobre los niveles de estrés en su trabajo.
  • Facilidad_transporte: Facilidad para trasladarse al lugar de trabajo.
  • Zona_trabajo_comoda: Comodidad de la zona de trabajo.
  • Permanencia_form_futuro: Intención del empleado de permanecer en la empresa a futuro.
  • Sufrido_situaciones_conflicto: Si el empleado ha experimentado situaciones de conflicto en el trabajo.
  • Molestias_puesto: Incomodidades físicas relacionadas con el puesto de trabajo.
  • Sentimiento_form: Sentimientos generales del empleado hacia la empresa.
  • Edad: Edad del empleado.
  • Género: Género del empleado.
  • Estado Civil: Estado civil del empleado.
  • Municipio: Municipio de residencia del empleado.
  • Nivel_escolar: Último nivel de estudios completado por el empleado.
  • Personas_dependientes: Número de personas que dependen económicamente del empleado.

Base de Datos: Nearshoring

  • Año: Año de registro de la información.
  • IED_Flujos_Reales: Inversión Extranjera Directa en flujos reales.
  • Exportaciones: Valor total de las exportaciones realizadas.
  • Educacion: Indicadores relacionados con la educación.
  • Salario_Diario: Salario diario promedio.
  • Innovacion: Indicadores de innovación y desarrollo tecnológico.
  • Inseguridad_Robo: Índices de robos.
  • Inseguridad_Homicidio: Índices de homicidios.
  • Tipo_de_Cambio: Valor del tipo de cambio.
  • Densidad_Carretera: Densidad de la red carretera.
  • Densidad_Poblacion: Densidad poblacional.
  • PIB_Per_Capita: Producto Interno Bruto per cápita.
  • INPC: Índice Nacional de Precios al Consumidor.
  • Empleo: Indicadores de empleo.
  • CO2_Emisiones: Emisiones de CO2.
  • Empresas_Extranjeras_Registradas: Número de empresas extranjeras registradas.
  • Población_Economicamente_Activa: Población económicamente activa.
  • Poblacion_ocupada_industria_manufacturera: Población ocupada en la industria manufacturera.
  • Poblacion_ocupada: Población ocupada en general.
  • Tasa_de_ocupacion_industria_manufacturera: Tasa de ocupación en la industria manufacturera.

Análisis Exploratorio de los Datos (EDA)

Desarrollar EDA que responda cada una de las preguntas de análisis.

Importando bases de datos

setwd("../databases/")
datos <- read_excel("form/Encuesta_Datos_FORM_Fall2023.xlsx")
df = read_xlsx("form/temporary/BDD_FORM_BAJAS-2023.xlsx")

datos_num <- datos
datos_num[sapply(datos_num, is.factor)] <- lapply(datos_num[sapply(datos_num, is.factor)], as.numeric)

a. Estadísticos Descriptivos

Analisis de Encuesta de Satisfacción

Estructura de la base de datos
str(datos_num)
## tibble [106 × 22] (S3: tbl_df/tbl/data.frame)
##  $ encuesta                     : num [1:106] 1 2 3 4 5 6 7 8 9 10 ...
##  $ puesto                       : chr [1:106] "administrativo" "costurera" "ayudante general" "ayudante general" ...
##  $ antiguedad                   : num [1:106] 9 36 4 2 1 36 36 36 36 1 ...
##  $ razon_entrada                : chr [1:106] "salario" "otro" "ubicacion empresa" "ubicacion empresa" ...
##  $ salario_bueno                : chr [1:106] "Totalmente de acuerdo" "Medianamente de acuerdo" "Medianamente en desacuerdo" "Totalmente de acuerdo" ...
##  $ prestaciones_bueno           : chr [1:106] "Medianamente de acuerdo" "Medianamente de acuerdo" "Totalmente en desacuerdo" "Medianamente de acuerdo" ...
##  $ jornada_no_excesiva          : chr [1:106] "Totalmente de acuerdo" "Totalmente de acuerdo" "Totalmente en desacuerdo" "Totalmente de acuerdo" ...
##  $ ofrecimiento_herramientas    : chr [1:106] "Totalmente de acuerdo" "Medianamente de acuerdo" "Totalmente en desacuerdo" "Totalmente de acuerdo" ...
##  $ no_molestia_temperatura      : chr [1:106] "Medianamente en desacuerdo" "Ni de acuerdo ni en desacuerdo" "Ni de acuerdo ni en desacuerdo" "Medianamente de acuerdo" ...
##  $ estres_bajo                  : chr [1:106] "Totalmente de acuerdo" "Medianamente en desacuerdo" "Totalmente en desacuerdo" "Totalmente de acuerdo" ...
##  $ facilidad_transporte         : chr [1:106] "Medianamente de acuerdo" "Medianamente en desacuerdo" "Medianamente de acuerdo" "Totalmente de acuerdo" ...
##  $ zona_trabajo_comoda          : chr [1:106] "Totalmente de acuerdo" "Medianamente de acuerdo" "Medianamente de acuerdo" "Totalmente de acuerdo" ...
##  $ permanencia_form_futuro      : chr [1:106] "Medianamente de acuerdo" "Totalmente de acuerdo" "Totalmente en desacuerdo" "Medianamente de acuerdo" ...
##  $ sufrido_situaciones_conflicto: chr [1:106] "No" "No" "Si" "No" ...
##  $ molestias_puesto             : chr [1:106] "cotizacion imss fecha pago comer 3pm" NA "trabajo estres" "bien" ...
##  $ sentimiento_form             : chr [1:106] "comodo contento" "comodo" "comoda contento" "comodo contento" ...
##  $ edad                         : chr [1:106] "30" "54" "21" "20" ...
##  $ genero                       : chr [1:106] "Femenino" "Femenino" "Femenino" "Femenino" ...
##  $ estado_civil                 : chr [1:106] "Unión libre" "Casado" "Soltero" "Casado" ...
##  $ municipio                    : chr [1:106] "Apodaca" "Apodaca" "Apodaca" "Apodaca" ...
##  $ nivel_escolar                : chr [1:106] "Licenciatura" "Primaria" "Preparatoria" "Preparatoria" ...
##  $ personas_dependientes        : num [1:106] 0 0 0 0 0 2 1 0 0 2 ...
Medidas Descriptivas
summary(datos_num)
##     encuesta         puesto            antiguedad    razon_entrada     
##  Min.   :  1.00   Length:106         Min.   : 1.00   Length:106        
##  1st Qu.: 27.25   Class :character   1st Qu.: 1.00   Class :character  
##  Median : 53.50   Mode  :character   Median : 9.00   Mode  :character  
##  Mean   : 53.50                      Mean   :14.08                     
##  3rd Qu.: 79.75                      3rd Qu.:34.50                     
##  Max.   :106.00                      Max.   :36.00                     
##  salario_bueno      prestaciones_bueno jornada_no_excesiva
##  Length:106         Length:106         Length:106         
##  Class :character   Class :character   Class :character   
##  Mode  :character   Mode  :character   Mode  :character   
##                                                           
##                                                           
##                                                           
##  ofrecimiento_herramientas no_molestia_temperatura estres_bajo       
##  Length:106                Length:106              Length:106        
##  Class :character          Class :character        Class :character  
##  Mode  :character          Mode  :character        Mode  :character  
##                                                                      
##                                                                      
##                                                                      
##  facilidad_transporte zona_trabajo_comoda permanencia_form_futuro
##  Length:106           Length:106          Length:106             
##  Class :character     Class :character    Class :character       
##  Mode  :character     Mode  :character    Mode  :character       
##                                                                  
##                                                                  
##                                                                  
##  sufrido_situaciones_conflicto molestias_puesto   sentimiento_form  
##  Length:106                    Length:106         Length:106        
##  Class :character              Class :character   Class :character  
##  Mode  :character              Mode  :character   Mode  :character  
##                                                                     
##                                                                     
##                                                                     
##      edad              genero          estado_civil        municipio        
##  Length:106         Length:106         Length:106         Length:106        
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##  nivel_escolar      personas_dependientes
##  Length:106         Min.   :0.000        
##  Class :character   1st Qu.:0.000        
##  Mode  :character   Median :1.000        
##                     Mean   :1.085        
##                     3rd Qu.:2.000        
##                     Max.   :3.000
describe(datos_num)
##                                vars   n  mean    sd median trimmed   mad min
## encuesta                          1 106 53.50 30.74   53.5   53.50 39.29   1
## puesto*                           2 106  4.84  4.12    3.0    4.27  2.97   1
## antiguedad                        3 106 14.08 14.47    9.0   13.05 11.86   1
## razon_entrada*                    4 106  4.00  1.83    4.0    4.12  2.97   1
## salario_bueno*                    5 106  2.83  1.49    3.0    2.79  1.48   1
## prestaciones_bueno*               6 106  3.12  1.46    4.0    3.15  1.48   1
## jornada_no_excesiva*              7 106  3.33  1.26    4.0    3.43  0.00   1
## ofrecimiento_herramientas*        8 106  3.64  1.23    4.0    3.79  0.00   1
## no_molestia_temperatura*          9 106  3.69  1.35    4.0    3.85  1.48   1
## estres_bajo*                     10 106  3.17  1.33    4.0    3.21  1.48   1
## facilidad_transporte*            11 106  4.04  1.48    5.0    4.28  0.00   1
## zona_trabajo_comoda*             12 106  3.43  1.23    4.0    3.56  0.00   1
## permanencia_form_futuro*         13 106  3.25  1.29    4.0    3.33  0.00   1
## sufrido_situaciones_conflicto*   14 106  1.31  0.72    1.0    1.15  0.00   1
## molestias_puesto*                15  88 30.70 19.56   28.5   29.97 27.43   1
## sentimiento_form*                16 106 13.51 10.12    7.0   12.01  4.45   1
## edad*                            17 106 17.41 11.63   15.5   16.88 14.08   1
## genero*                          18 106  1.35  0.48    1.0    1.31  0.00   1
## estado_civil*                    19 106  2.46  1.16    3.0    2.45  1.48   1
## municipio*                       20 106  1.76  1.42    1.0    1.43  0.00   1
## nivel_escolar*                   21 106  3.42  1.58    3.0    3.51  2.97   1
## personas_dependientes            22 106  1.08  1.10    1.0    0.99  1.48   0
##                                max range  skew kurtosis   se
## encuesta                       106   105  0.00    -1.23 2.99
## puesto*                         14    13  1.11    -0.23 0.40
## antiguedad                      36    35  0.61    -1.36 1.41
## razon_entrada*                   6     5 -0.38    -1.37 0.18
## salario_bueno*                   5     4 -0.12    -1.62 0.14
## prestaciones_bueno*              5     4 -0.23    -1.42 0.14
## jornada_no_excesiva*             5     4 -0.95    -0.52 0.12
## ofrecimiento_herramientas*       5     4 -1.20     0.38 0.12
## no_molestia_temperatura*         5     4 -0.89    -0.44 0.13
## estres_bajo*                     5     4 -0.50    -1.03 0.13
## facilidad_transporte*            5     4 -1.20    -0.23 0.14
## zona_trabajo_comoda*             5     4 -1.16    -0.12 0.12
## permanencia_form_futuro*         5     4 -0.79    -0.75 0.13
## sufrido_situaciones_conflicto*   3     2  1.87     1.56 0.07
## molestias_puesto*               67    66  0.26    -1.29 2.09
## sentimiento_form*               40    39  1.18     0.13 0.98
## edad*                           40    39  0.33    -1.24 1.13
## genero*                          2     1  0.62    -1.63 0.05
## estado_civil*                    4     3 -0.23    -1.51 0.11
## municipio*                       6     5  1.73     1.75 0.14
## nivel_escolar*                   5     4 -0.42    -1.33 0.15
## personas_dependientes            3     3  0.48    -1.18 0.11

b. Medidas de Dispersión

Medidas de Dispersión

Cálculo de medidas de dispersión para cada variable numérica relevante

sapply(datos_num, var, na.rm = TRUE)  # Varianza
##                      encuesta                        puesto 
##                    945.166667                            NA 
##                    antiguedad                 razon_entrada 
##                    209.422821                            NA 
##                 salario_bueno            prestaciones_bueno 
##                            NA                            NA 
##           jornada_no_excesiva     ofrecimiento_herramientas 
##                            NA                            NA 
##       no_molestia_temperatura                   estres_bajo 
##                            NA                            NA 
##          facilidad_transporte           zona_trabajo_comoda 
##                            NA                            NA 
##       permanencia_form_futuro sufrido_situaciones_conflicto 
##                            NA                            NA 
##              molestias_puesto              sentimiento_form 
##                            NA                            NA 
##                          edad                        genero 
##                    148.990293                            NA 
##                  estado_civil                     municipio 
##                            NA                            NA 
##                 nivel_escolar         personas_dependientes 
##                            NA                      1.202246
sapply(datos_num, sd, na.rm = TRUE)   # Desviación estándar
##                      encuesta                        puesto 
##                      30.74356                            NA 
##                    antiguedad                 razon_entrada 
##                      14.47145                            NA 
##                 salario_bueno            prestaciones_bueno 
##                            NA                            NA 
##           jornada_no_excesiva     ofrecimiento_herramientas 
##                            NA                            NA 
##       no_molestia_temperatura                   estres_bajo 
##                            NA                            NA 
##          facilidad_transporte           zona_trabajo_comoda 
##                            NA                            NA 
##       permanencia_form_futuro sufrido_situaciones_conflicto 
##                            NA                            NA 
##              molestias_puesto              sentimiento_form 
##                            NA                            NA 
##                          edad                        genero 
##                      12.20616                            NA 
##                  estado_civil                     municipio 
##                            NA                            NA 
##                 nivel_escolar         personas_dependientes 
##                            NA                       1.09647

Cálculo del rango intercuartílico para cada variable numérica relevante

sapply(datos_num, IQR, na.rm = TRUE)
##                      encuesta                        puesto 
##                          52.5                            NA 
##                    antiguedad                 razon_entrada 
##                          33.5                            NA 
##                 salario_bueno            prestaciones_bueno 
##                            NA                            NA 
##           jornada_no_excesiva     ofrecimiento_herramientas 
##                            NA                            NA 
##       no_molestia_temperatura                   estres_bajo 
##                            NA                            NA 
##          facilidad_transporte           zona_trabajo_comoda 
##                            NA                            NA 
##       permanencia_form_futuro sufrido_situaciones_conflicto 
##                            NA                            NA 
##              molestias_puesto              sentimiento_form 
##                            NA                            NA 
##                          edad                        genero 
##                          20.0                            NA 
##                  estado_civil                     municipio 
##                            NA                            NA 
##                 nivel_escolar         personas_dependientes 
##                            NA                           2.0

c. 4-6 Gráficos (barras, líneas, pastel, dispersión, burbujas, correlación, mapas)

Relación entre el Nivel de Estrés y Puesto de Trabajo
ggplot(datos, aes(x = reorder(puesto, estres_bajo, FUN = median), y = estres_bajo)) +
  geom_bar(stat = "summary", fun = "median", fill = "orange", color = "black") +
  coord_flip() +  # Invertir ejes para tener los puestos en el eje y y las barras extendiéndose horizontalmente
  theme_minimal() +
  labs(title = "Nivel de Estrés con base en Media por Puesto de Trabajo",
       y = "Nivel de Estrés Mediano",
       x = "Puesto") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

En esta gráfica de barras podemos observar diferentes puestos de trabajo y su correspondiente nivel mediano de estrés.

Los puestos con niveles más altos de estrés parecen ser soldador,otro, y operador. Un hallazgo importante es que estos puestos pueden tener condiciones de trabajo que generan un alto nivel de estrés, lo que podría estar contribuyendo a la rotación de personal. La empresa FORM podría enfocarse en mejorar las condiciones de trabajo en estos puestos, tal vez automatizando tareas estresantes o proporcionando más apoyo y descansos.

Los puestos con menores niveles de estrés son asistente de producción,embarque, y mantenimiento, lo que podría indicar que estas áreas son menos propensas a experimentar rotación debido al estrés laboral.

Relación entre la Antigüedad y el Salario
antiguedad_por_salario <- datos %>%
  group_by(salario_bueno) %>%
  summarise(antiguedad_promedio = mean(antiguedad, na.rm = TRUE)) %>%
  arrange(desc(antiguedad_promedio))

# Definir una paleta de colores personalizada
colores_personalizados <- c('Totalmente de acuerdo' = '#AED6F1', # Claro
                            'Medianamente de acuerdo' = '#5DADE2', # Intermedio claro
                            'Ni de acuerdo ni en desacuerdo' = '#3498DB', # Neutro
                            'Medianamente en desacuerdo' = '#2874A6', # Intermedio oscuro
                            'Totalmente en desacuerdo' = '#1B4F72') # Oscuro

# Gráfico de barras de la antigüedad promedio por satisfacción con el salario, usando colores personalizados
ggplot(antiguedad_por_salario, aes(x = salario_bueno, y = antiguedad_promedio, fill = salario_bueno)) +
  geom_bar(stat = "identity") +
  scale_fill_manual(values = colores_personalizados) + # Usa la paleta de colores personalizada
  coord_flip() +
  theme_minimal() +
  labs(title = "Antigüedad Promedio por Satisfacción con el Salario",
       x = "Satisfacción con el Salario",
       y = "Antigüedad Promedio (años)"
)

Esta gráfica de barras verticales ilustra la relación entre la antigüedad promedio en la empresa y el grado de satisfacción con el salario. Se observa una correlación positiva entre la antigüedad y la satisfacción salarial, destacando que los empleados que están totalmente satisfechos con su salario tienden a tener una mayor antigüedad, específicamente entre 15 a 20 años.

Este patrón sugiere que la satisfacción salarial incrementa con el tiempo de servicio en la empresa. Esto podría interpretarse como una señal de que los aumentos salariales o bonificaciones basadas en la antigüedad son efectivos, o bien, que los empleados de mayor antigüedad ocupan puestos con mejor remuneración, posiblemente debido a ascensos o incrementos salariales vinculados a su desempeño a lo largo de los años.

Ante estos hallazgos, se recomienda a la empresa FORM considerar modificaciones en su estructura salarial para incrementar la satisfacción salarial entre los empleados de menor antigüedad. Tal ajuste podría contribuir a reducir la rotación de personal, fomentando un ambiente laboral más estable y comprometido.

Percepción de Molestia por la Temperatura por Puesto
datos %>%
  group_by(puesto, no_molestia_temperatura) %>%
  summarise(count = n()) %>%
  ggplot(aes(x = puesto, y = count, fill = no_molestia_temperatura)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(title = "Percepción de Molestia por la Temperatura por Puesto",
       x = "Puesto",
       y = "Cantidad",
       fill = "No Molesta la Temperatura") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Hemos observado una notable incomodidad con la temperatura por parte de los ayudantes generales, lo cual requiere que tomemos medidas para regular el clima en el espacio donde desempeñan sus labores. Esta situación no parece ser tan pronunciada en otras áreas.

Disconformidad por Puesto
datos %>% 
  group_by(puesto, permanencia_form_futuro) %>% 
  summarise(count = n()) %>%
  filter(permanencia_form_futuro != "Totalmente de acuerdo" & permanencia_form_futuro != "Medianamente de acuerdo") %>%
  ggplot(aes(x = reorder(puesto, -count), y = count, fill = permanencia_form_futuro)) +
  geom_bar(stat = "identity") +
  coord_flip() +
  labs(title = "Disconformidad por Puesto",
       x = "Puesto",
       y = "Cantidad de Disconformidad") +
  theme_minimal()

Percepción del Estrés por Rangos de Antigüedad
datos$antiguedad_rango <- cut(datos$antiguedad, breaks = seq(0, max(datos$antiguedad, na.rm = TRUE) + 5, by = 5), right = FALSE, labels = paste(seq(0, max(datos$antiguedad, na.rm = TRUE), by = 5), seq(5, max(datos$antiguedad, na.rm = TRUE) + 5, by = 5) - 1, sep = "-"))
datos %>%
  group_by(antiguedad_rango, estres_bajo) %>%
  summarise(count = n()) %>%
  ggplot(aes(x = antiguedad_rango, y = count, fill = estres_bajo)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(title = "Percepción del Estrés por Rangos de Antigüedad",
       x = "Rango de Antigüedad",
       y = "Cantidad",
       fill = "Percepción de Bajo Estrés") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Contamos con indicios sólidos de que el estrés no constituye un factor adverso para nuestros trabajadores. Observamos que la mayoría, sin importar su tiempo de servicio en la empresa, reporta experimentar un nivel bajo de estrés en sus actividades laborales.

Percepción de Prestaciones por Puesto
datos %>%
  group_by(puesto, prestaciones_bueno) %>%
  summarise(count = n()) %>%
  ggplot(aes(x = puesto, y = count, fill = prestaciones_bueno)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(title = "Percepción de Prestaciones por Puesto",
       x = "Puesto",
       y = "Cantidad",
       fill = "Hay Buenas Prestaciones") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Observamos que entre los ayudantes generales se concentra la mayor cantidad de respuestas en nuestra base de datos, lo cual indica que este grupo es el más numeroso. Dentro de este colectivo, las opiniones sobre las prestaciones ofrecidas por la empresa son variadas. Este fenómeno sugiere que los ayudantes generales no están completamente satisfechos con las prestaciones que reciben; de lo contrario, no observaríamos tal diversidad en las respuestas.

Por tanto, se puede concluir que una de las principales áreas de mejora para la empresa reside en el trato hacia los ayudantes generales, quienes expresan descontento principalmente con la temperatura en su lugar de trabajo y perciben que las prestaciones que reciben no son adecuadas. Esta situación podría estar contribuyendo a la alta rotación observada en este sector de la empresa.

d. Tablas (frequencia, contingencia)

Analisis de Bajas de FORM

summary(df)
##       No.         Apellidos            Nombre          Fecha de Nacimiento
##  Min.   :1.000   Length:279         Length:279         Min.   :23715      
##  1st Qu.:1.000   Class :character   Class :character   1st Qu.:31334      
##  Median :1.000   Mode  :character   Mode  :character   Median :35103      
##  Mean   :1.022                                         Mean   :33817      
##  3rd Qu.:1.000                                         3rd Qu.:36932      
##  Max.   :4.000                                         Max.   :44865      
##                                                                           
##     Género              RFC            Fecha de Alta     Primer Mes   
##  Length:279         Length:279         Min.   :43070   Min.   :43100  
##  Class :character   Class :character   1st Qu.:44936   1st Qu.:44966  
##  Mode  :character   Mode  :character   Median :45003   Median :45033  
##                                        Mean   :44970   Mean   :45001  
##                                        3rd Qu.:45098   3rd Qu.:45128  
##                                        Max.   :45161   Max.   :45191  
##                                                                       
##    Cuarto Mes    Fecha de Baja   Motivo de Baja        Puesto         
##  Min.   :43190   Min.   :44928   Length:279         Length:279        
##  1st Qu.:45058   1st Qu.:45001   Class :character   Class :character  
##  Median :45125   Median :45078   Mode  :character   Mode  :character  
##  Mean   :45092   Mean   :45063                                        
##  3rd Qu.:45220   3rd Qu.:45124                                        
##  Max.   :45283   Max.   :45166                                        
##                                                                       
##      Dpto               Imss                SD           
##  Length:279         Length:279         Length:279        
##  Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character  
##                                                          
##                                                          
##                                                          
##                                                          
##  Factor de Crédito Infonavit No. De Crédito Infonavit     CURP          
##  Length:279                  Length:279               Length:279        
##  Class :character            Class :character         Class :character  
##  Mode  :character            Mode  :character         Mode  :character  
##                                                                         
##                                                                         
##                                                                         
##                                                                         
##     Calle              Número            Colonia           Municipio        
##  Length:279         Length:279         Length:279         Length:279        
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##                                                                             
##     Estado                CP        Estado Civil       Número de Télefono 
##  Length:279         Min.   :25115   Length:279         Min.   :8.320e+07  
##  Class :character   1st Qu.:66646   Class :character   1st Qu.:8.118e+09  
##  Mode  :character   Median :66646   Mode  :character   Median :8.129e+09  
##                     Mean   :65419                      Mean   :7.989e+09  
##                     3rd Qu.:66652                      3rd Qu.:8.136e+09  
##                     Max.   :99999                      Max.   :9.841e+09  
##                                                        NA's   :12
df <- df %>% 
  mutate(Dpto = if_else(Dpto == "Produccion Cartón MC", "Producción Cartón MC", Dpto))
Bajas por Departamento
bajas_por_departamento <- df %>%
  group_by(Dpto) %>%
  summarise(Total_Bajas = n())

ggplot(bajas_por_departamento, aes(x = reorder(Dpto, -Total_Bajas), y = Total_Bajas, fill = Dpto)) +
  geom_bar(stat = "identity") +
  theme_minimal() +
  labs(title = "Bajas por Departamento", x = "Departamento", y = "Total de Bajas")

bajas_por_departamento <- df %>%
  group_by(Dpto) %>%
  summarise(Total_Bajas = n()) %>%
  filter(Total_Bajas > 1)

# Ordenamos las bajas por departamento de mayor a menor en el gráfico
ggplot(bajas_por_departamento, aes(x = reorder(Dpto, -Total_Bajas), y = Total_Bajas, fill = Dpto)) +
  geom_bar(stat = "identity") +
  theme_minimal() +
  labs(title = "Bajas por Departamento (Filtrado)", x = "Departamento", y = "Total de Bajas")

Bajas por Departamento y Género
bajas_por_departamento_genero <- df %>%
  group_by(Dpto, Género) %>%
  summarise(Total_Bajas = n())

ggplot(bajas_por_departamento_genero, aes(x = reorder(Dpto, -Total_Bajas), y = Total_Bajas, fill = Género)) +
  geom_bar(stat = "identity", position = "dodge") +
  theme_minimal() +
  labs(title = "Bajas por Departamento y Género", x = "Departamento", y = "Total de Bajas")

bajas_por_departamento_genero <- df %>%
  group_by(Dpto, Género) %>%
  summarise(Total_Bajas = n()) %>%
  filter(Total_Bajas > 1)

ggplot(bajas_por_departamento_genero, aes(x = reorder(Dpto, -Total_Bajas), y = Total_Bajas, fill = Género)) +
  geom_bar(stat = "identity", position = "dodge") +
  theme_minimal() +
  labs(title = "Bajas por Departamento y Género (Filtrado)", x = "Departamento", y = "Total de Bajas")

Bajas por Motivo y Género
bajas_por_motivo_genero <- df %>%
  group_by(`Motivo de Baja`, Género) %>%
  summarise(Total_Bajas = n())

ggplot(bajas_por_motivo_genero, aes(x = `Motivo de Baja`, y = Total_Bajas, fill = Género)) +
  geom_bar(stat = "identity", position = "dodge") +
  theme_minimal() +
  labs(title = "Bajas por Motivo y Género", x = "Motivo de Baja", y = "Total de Bajas") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Las gráficas muestran que los departamentos de Producción de Cartón, tanto MC como ML, registran el mayor número de bajas en la empresa. Este dato resalta la existencia de un problema significativo en estas áreas, subrayando la urgencia de investigar las causas subyacentes para implementar estrategias correctivas adecuadas.

Además, es notable que, de las 18 personas que dejaron la empresa, 17 fueran mujeres. Este desproporcionado impacto sobre las trabajadoras sugiere la presencia de un problema serio relacionado con cuestiones de género. Identificar y abordar las dinámicas o condiciones laborales que puedan estar contribuyendo a esta situación es crucial para crear un entorno de trabajo más inclusivo y equitativo.

df$`Fecha de Baja` <- as.Date(df$`Fecha de Baja`, origin = "1899-12-30")

df$AñoMes <- format(df$`Fecha de Baja`, "%Y-%m")
Tendencia de Bajas a lo Largo del Tiempo
bajas_por_fecha <- df %>%
  group_by(AñoMes) %>%
  summarise(Total_Bajas = n())

ggplot(bajas_por_fecha, aes(x = AñoMes, y = Total_Bajas, group = 1)) +
  geom_line() +
  geom_point() +
  theme_minimal() +
  labs(title = "Tendencia de Bajas a lo Largo del Tiempo", x = "Año y Mes", y = "Total de Bajas") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Bajas Totales por Mes
df$`Fecha de Baja` <- as.Date(df$`Fecha de Baja`, origin = "1899-12-30")

bajas_por_mes <- df %>%
  mutate(Mes = format(`Fecha de Baja`, "%B")) %>%
  group_by(Mes) %>%
  summarise(Total_Bajas = n())

meses <- format(seq(as.Date("2000-01-01"), as.Date("2000-12-01"), by = "month"), "%B")
bajas_por_mes$Mes <- factor(bajas_por_mes$Mes, levels = meses)

# Ahora ordenamos los datos para el gráfico
bajas_por_mes <- bajas_por_mes %>%
  mutate(Mes = reorder(Mes, -Total_Bajas))

# Gráfico de barras mostrando las bajas totales por mes, ordenadas de mayor a menor
ggplot(bajas_por_mes, aes(x = Mes, y = Total_Bajas, fill = Mes)) +
  geom_bar(stat = "identity") +
  theme_minimal() +
  labs(title = "Bajas Totales por Mes Ordenadas", x = "Mes", y = "Total de Bajas")

A pesar de la ausencia de datos de marzo a mayo, la evidencia sugiere que no se registraron bajas en la empresa durante ese periodo. Sin embargo, se observa un notable aumento en las bajas en junio, lo cual es significativo y merece una exploración detallada. Este incremento podría estar vinculado a factores legales relacionados con contratos o, posiblemente, estar asociado a problemas específicos en el área de producción de cartón, dado que la mayoría de las bajas ese mes se atribuyen a esta última razón.

Es imperativo llevar a cabo un análisis más profundo para comprender con mayor precisión las causas subyacentes de este fenómeno. Dicho análisis ayudará a identificar las áreas críticas de intervención y a desarrollar estrategias efectivas para prevenir futuras bajas en estos departamentos críticos.

bajas_por_estado_civil <- df %>%
  group_by(`Estado Civil`) %>%
  summarise(Total_Bajas = n()) %>%
  mutate(`Estado Civil` = reorder(`Estado Civil`, -Total_Bajas))

ggplot(bajas_por_estado_civil, aes(x = `Estado Civil`, y = Total_Bajas, fill = `Estado Civil`)) +
  geom_bar(stat = "identity") +
  theme_minimal() +
  labs(title = "Bajas por Estado Civil", x = "Estado Civil", y = "Total de Bajas") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Se destaca claramente que las personas solteras presentan una mayor tasa de bajas en la empresa. Este patrón podría deberse a la menor cantidad de responsabilidades familiares o dependientes económicos, lo que les otorga mayor flexibilidad para tomar decisiones sobre su carrera profesional sin tener que considerar el impacto en otros miembros de una familia.

Análisis de Sentimiento

Las 2 tendencias de las emociones son: Positiva o Negativa

# Función ajustada para preprocesar texto
preparar_texto <- function(datos, columna) {
  datos %>%
    select(!!sym(columna)) %>%
    mutate(across(everything(), as.character)) %>%
    mutate(across(everything(), ~ gsub("\\d+", "", .))) %>%
    unnest_tokens(word, !!sym(columna))
}

# Función ajustada para análisis de sentimiento y wordcloud
analizar_y_wordcloud <- function(datos, columna) {
  texto_preparado <- preparar_texto(datos, columna)
  
  # Obtener sentimiento
  emociones_df <- texto_preparado %>%
    inner_join(get_sentiments("nrc"), by = "word") %>%
    count(sentiment, sort = TRUE) %>%
    print()
  
  # Filtrar palabras para el wordcloud (aparición mínima: 3 veces)
  palabras_frecuentes <- texto_preparado %>%
    count(word, sort = TRUE) %>%
    filter(n >= 3)
  
  # Generar wordcloud
  set.seed(123)
  wordcloud(words = palabras_frecuentes$word, freq = palabras_frecuentes$n, min.freq = 2,
            max.words = 100, random.order = FALSE, rot.per = 0.35, 
            colors = brewer.pal(8, "Dark2"))
}
analizar_y_wordcloud(datos, "razon_entrada")
## # A tibble: 0 × 2
## # ℹ 2 variables: sentiment <chr>, n <int>

analizar_y_wordcloud(datos, "molestias_puesto")
## # A tibble: 2 × 2
##   sentiment     n
##   <chr>     <int>
## 1 trust         3
## 2 negative      2

analizar_y_wordcloud(datos, "sentimiento_form")
## # A tibble: 2 × 2
##   sentiment     n
##   <chr>     <int>
## 1 trust         2
## 2 positive      1

El análisis del sentimiento general revela una actitud positiva dentro de la empresa, probablemente influenciada por el método de recolección de datos utilizado, que se basó en una pregunta abierta respondida por los colaboradores. Se sugiere que este formato puede hacer que sea más difícil para los empleados expresar sentimientos negativos de forma concisa, en tan solo tres palabras, lo que podría llevar a una representación más positiva del ambiente laboral en los resultados del análisis.

e. Pronóstico de ventas (e.g., unidades de producción, ventas en $)

ts_plot(Ventas)

Interpretación Interpretar los hallazgos identificados en el desarrollo de EDA para responder las preguntas de análisis.

La interpretación comprensiva de los hallazgos revela una complejidad subyacente en la percepción y realidades del ambiente laboral en la empresa FORM. A pesar de la aparente actitud positiva general, se identifican desafíos específicos y oportunidades de mejora. Principales insights y recomendaciones incluyen:

  • Insights Principales:
    • La metodología de recolección de datos puede influir en la percepción positiva general del ambiente laboral, sugiriendo la posibilidad de un sesgo en las respuestas obtenidas.
    • Las altas tasas de baja entre el personal soltero y los departamentos específicos, como Producción de Cartón, apuntan a necesidades y preocupaciones únicas en estas poblaciones.
    • Una desproporción significativa en las bajas de mujeres resalta problemas potenciales de género que necesitan ser abordados para mejorar la equidad en el lugar de trabajo.
    • La correlación positiva entre la antigüedad y la satisfacción salarial enfatiza la importancia de las políticas de retención y recompensa basadas en la lealtad y el tiempo de servicio.
  • Recomendaciones Generales para la Empresa FORM:
    • Mejorar las Condiciones de Trabajo: Priorizar la regulación de la temperatura en áreas críticas y examinar otras condiciones laborales que pueden estar afectando negativamente la satisfacción del empleado.
    • Ajustar la Estructura Salarial: Considerar revisiones en la estructura salarial para mejorar la satisfacción entre los empleados de menor antigüedad, potencialmente reduciendo la rotación.
    • Enfocarse en la Equidad de Género: Implementar políticas específicas para abordar y mejorar las dinámicas de género, asegurando un entorno de trabajo inclusivo y equitativo para todos los empleados.

Estas recomendaciones apuntan a fortalecer el ambiente laboral en FORM, abordando tanto los desafíos identificados como aprovechando las áreas de fortaleza para fomentar un entorno más positivo y productivo.

Búsqueda de información y datos

  • ¿Qué tipo de información / datos solicitarías al socio formador para mejorar EDA?

Para poder tener un Análisis Exploratorio de los Datos completo, debemos de desarrollar soluciones efectivas a los problemas de la empresa, principalmente en la rotación de personal y la predicción de la demanda en producción es por eso que pediríamos información como:

  1. Información detallada sobre las bases de datos, como base de datos completa de personal. También, en la base de datos de ventas incluir más información, ya que cuenta con NA, lo que hace complicaciones en el análisis, que no podamos trabajar con muy pocos datos y eso limita nuestro trabajo para poder seguir identificando hallazgos importantes para la empresa

  2. Data de encuestas de bajas, sobre todo incluyendo las razones de la renuncia para poder detectar diferentes tendencias y patrones.

  3. Un Análisis Demográfico para saber datos de la edad, género, situación familiar y ubicación geográfica de los empleados para poder relacionar patrones con la rotación que existe en FORM.

De forma más simple, los datos explicitos más necesarios son: -⁠ ⁠BASE DATOS COMPLETA DE PERSONAL -⁠ ⁠DATA DE ENCUESTAS DE RAZON DE BAJAS -⁠ ⁠DATA DE TIEMPOS DE INVENTARIO -⁠ ⁠DATA DE DESGLOSE DE VENTA DE UNIDADES POR CLIENTE / O POR TIPO DE PARTE

  • ¿Qué tipo de información / datos de fuentes secundarias buscarías para mejorar EDA?

Para complementar el EDA, con información de fuentes externas, buscamos información en:

  1. Informes de la Industria (Statista) debido a que nos proporciona estadísticas globales sobre la industria automotriz. incluyendo las tendencias tecnológicas.

  2. Estudios sobre el mercado de los empaques (Smithers) publican análisis de tendencias e informes de mercado de los empaques que se utilizan en el sector automotriz.

  3. Datos de Comercio Internacional y económicos (Banco Mundial) para los datos de tarifas y economía global que afectan el comercio de los empaques

  4. (Hoovers) para un Análisis de Competencia, donde se ofrecen datos importantes sobre las empresas y un análisis detallado de competidores en la industria de empaques.

  • (Opcional) Buscar información / datos de fuentes secundarias (por ejemplo, INEGI, Industria Nacional de Autopartes, etc.) que contribuyan a mejorar EDA y la identificación de hallazgos releventes que respondan las preguntas de análisis. Citar las fuentes secundarias seleccionadas.

Para tener un análisis más detallado buscamos información en diferentes fuentes:

1. Crecimiento del Sector Automotriz, en el 2024 se espera que la cifra de vehículos comercializados en México incremente en un 8% y esto representa 100 mil unidades más que en el 2023. En 2023 tuvo un crecimiento del 24.4% en vehículos comercializados comparado con el 2022. (Mexico Industry, 2024). Estos datos son un potencial aumento de demanda en los empaques de autopartes lo que es un impacto positivo para FORM.

2. Impacto en la electromovilidad, ya que existe una transición hacia la electromovilidad y esto genera una oportunidad para la creación de empleos y la demanda de competencias especializadas, esto impacta e influye de manera significativa a la demanda de empaques para los autopartes y componentes electrónicos y sistemas avanzados en los automóviles.

##Referencias

#1. D&B Hoovers is Your Sales Accelerator – Dun & Bradstreet. (s. f.). Recuperado 16 de marzo de 2024, de https://www.dnb.com/products/dnb-hoovers.html

#2. World Bank Group - International Development, Poverty, & Sustainability. (s. f.). World Bank. Recuperado 16 de marzo de 2024, de https://www.worldbank.org/en/home

#3. Smithers - Innovate with confidence. (s. f.). Smithers. Recuperado 16 de marzo de 2024, de https://www.smithers.com/home

#4. Statista. (s. f.). Statista - the statistics portal. Recuperado 16 de marzo de 2024, de https://www.statista.com/

#5. MexicoIndustry. (s. f.). Incrementará 8% el sector automotriz en 2024*. MexicoIndustry. Recuperado 16 de marzo de 2024, de https://mexicoindustry.com/noticia/incrementara-8-el-sector-automotriz-en-2024

#6. Newsroom Infobae. (2023, 12 abril). Industria automotriz en México espera más empleos por electromovilidad. Infobae*. Recuperado 16 de marzo de 2024, de https://www.infobae.com/america/agencias/2023/04/12/industria-automotriz-en-mexico-espera-mas-empleos-por-electromovilidad/

LS0tCnRpdGxlOiAiRm9ybS1EZWxpdmVyYWJsZTIiCmF1dGhvcjogIkRhdmlkIERvbWluZ3VleiAtIEEwMTU3MDk3NSwgQWxlamFuZHJhIFN1w6FyZXogLSBBMDA4MzUyNDcsIERhbmllbCBOw6FqZXJhIC0gQTAxNzA5NTc4LCBFZHVhcmRvIENhbWFjaG8gLSBBMDEwMjY0MzcsIEdhYnJpZWwgTWVkaW5hIC0gQTAxMjc1NzYzIgpkYXRlOiAiMjAyNC0wMy0xMyIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiBUUlVFCiAgICB0b2NfZmxvYXQ6IFRSVUUKICAgIGNvZGVfZG93bmxvYWQ6IFRSVUUKICAgIHRoZW1lOiBjb3NtbwotLS0KCiFbRk9STSBCQU5ORVJdKC9Vc2Vycy9kYXZpZGRydW1zMTgwL1RlYy9DYXNlX1N0dWR5X0Zvcm0vc3JjL2Zvcm0uanBnKQoKQ0QyMDAxQyAtLSBBbmFsw610aWNhIHBhcmEgTmVnb2Npb3M6IERlIExvcyBEYXRvcyBhIGxhcyBEZWNpc2lvbmVzIEZlYnJlcm8gLS0gSnVuaW8gMjAyNAoKIyBFbnRyZWdhYmxlIDIgLS0gRXZpZGVuY2lhIDEKCiMjIFNpdHVhY2nDs24gUHJvYmxlbWEgMTogUm90YWNpw7NuIGRlIFBlcnNvbmFsCgpFeHBsb3JhciwgZGVmaW5pciwgeSBkZXNjcmliaXIgY3XDoWxlcyBzb24gbG9zIHByaW5jaXBhbGVzIGZhY3RvcmVzIGRlbCBjbGltYSBvcmdhbml6YWNpb25hbCBkZSBGT1JNIHF1ZSBwcm9waWNpYW4gbGEgc2F0aXNmYWNjacOzbiB5L28gbm8gc2F0aXNmYWNjacOzbiBkZSB0cmFiYWphciBlbiBkaWNoYSBlbXByZXNhLgoKTGEgcm90YWNpw7NuIGRlIHBlcnNvbmFsIHNlIGhhIGlkZW50aWZpY2FkbyBjb21vIGVsIGRlc2Fmw61vIG3DoXMgY3LDrXRpY28gcXVlIGVuZnJlbnRhIEZPUk0gZW4gZWwgcHJlc2VudGUuIEEgcGVzYXIgZGUgbnVlc3Ryb3MgZXNmdWVyem9zIGNvbnRpbnVvcyBwYXJhIGNyZWFyIHVuIGFtYmllbnRlIGxhYm9yYWwgYXRyYWN0aXZvIHkgcmV0ZW5lciBhIG51ZXN0cm9zIHZhbGlvc29zIGVtcGxlYWRvcywgbm9zIGVuY29udHJhbW9zIGNvbiB1bmEgdGFzYSBkZSByb3RhY2nDs24gZXNwZWNpYWxtZW50ZSBhbHRhIGVudHJlIGxvcyBvcGVyYWRvcmVzLiBFc3RlIGZlbsOzbWVubyBubyBzb2xvIGFmZWN0YSBsYSBjb250aW51aWRhZCB5IGxhIGVmaWNpZW5jaWEgZGUgbnVlc3RyYXMgb3BlcmFjaW9uZXMsIHNpbm8gcXVlIHRhbWJpw6luIGluY3JlbWVudGEgbG9zIGNvc3RvcyBhc29jaWFkb3MgY29uIGVsIHJlY2x1dGFtaWVudG8geSBsYSBjYXBhY2l0YWNpw7NuIGRlIG51ZXZvIHBlcnNvbmFsLgoKLSAgICoqUHJpbmNpcGFsZXMgUHVudG9zOioqCiAgICAtICAgTGEgZXN0YWJpbGlkYWQgZmFtaWxpYXIgeSBsYXMgY29uZGljaW9uZXMgbGFib3JhbGVzIHNvbiBmYWN0b3JlcyBzaWduaWZpY2F0aXZvcyBxdWUgaW5mbHV5ZW4gZW4gbGEgZGVjaXNpw7NuIGRlIGxvcyBlbXBsZWFkb3MgZGUgcGVybWFuZWNlciBlbiBsYSBlbXByZXNhLgogICAgLSAgIExvcyBqw7N2ZW5lcywgZXNwZWNpYWxtZW50ZSBhcXVlbGxvcyBzaW4gY29tcHJvbWlzb3MgZmFtaWxpYXJlcywgdGllbmRlbiBhIGJ1c2NhciBvcG9ydHVuaWRhZGVzIGRlIGRlc2Fycm9sbG8gcHJvZmVzaW9uYWwgZnVlcmEgZGUgRk9STS4KICAgIC0gICBFcyBjcnVjaWFsIG1lam9yYXIgbnVlc3RyYXMgZXN0cmF0ZWdpYXMgZGUgcmVjbHV0YW1pZW50byB5IHJldGVuY2nDs24gcGFyYSBhYm9yZGFyIGxhcyBjYXVzYXMgc3VieWFjZW50ZXMgZGUgbGEgcm90YWNpw7NuIGRlIHBlcnNvbmFsLgoKIyMgU2l0dWFjacOzbiBQcm9ibGVtYSAyOiBQcmVkaWNjacOzbiBkZSBEZW1hbmRhCgpFeHBsb3JhciwgZGVzYXJyb2xsYXIsIHkgZGVzY3JpYmlyIGxhKHMpIHBvc2libGUocykgZXN0cmF0ZWdpYShzKSBkZSBwcmVkaWNjacOzbiBkZSBsYSBkZW1hbmFkYSBkZSBwcm9kdWN0b3MgZmFicmljYWRvcyBwb3IgbGEgZW1wcmVzYSBGT1JNLgoKTGEgcHJlZGljY2nDs24gcHJlY2lzYSBkZSBsYSBkZW1hbmRhIHJlcHJlc2VudGEgdW4gZGVzYWbDrW8gaWd1YWxtZW50ZSBzaWduaWZpY2F0aXZvIHBhcmEgRk9STSwgZGFkYSBsYSB2YXJpYWJpbGlkYWQgaW5oZXJlbnRlIGVuIGxhIHByb2R1Y2Npw7NuIHkgdmVudGEgZGUgYXV0b3BhcnRlcy4gTGEgaGFiaWxpZGFkIHBhcmEgYW50aWNpcGFyIGNvbiBleGFjdGl0dWQgY3XDoW50YXMgdW5pZGFkZXMgZGUgdW4gZGV0ZXJtaW5hZG8gY29tcG9uZW50ZSBzZXLDoW4gbmVjZXNhcmlhcyBlcyBjcnVjaWFsIHBhcmEgb3B0aW1pemFyIG51ZXN0cm9zIHByb2Nlc29zIGRlIHByb2R1Y2Npw7NuIHkgZW1wYXF1ZSwgeSBwYXJhIGFzZWd1cmFyIHF1ZSBzZSBtYXhpbWljZSBsYSBlZmljaWVuY2lhIGVuIGVsIHVzbyBkZSByZWN1cnNvcy4KCi0gICAqKlByaW5jaXBhbGVzIFB1bnRvczoqKgogICAgLSAgIExhIG5hdHVyYWxlemEgZmx1Y3R1YW50ZSBkZSBsYSBkZW1hbmRhIGF1dG9tb3RyaXogY29tcGxpY2EgbGEgcGxhbmlmaWNhY2nDs24geSBnZXN0acOzbiBkZSBpbnZlbnRhcmlvcy4KICAgIC0gICBFcyBlc2VuY2lhbCBkZXNhcnJvbGxhciBoZXJyYW1pZW50YXMgeSBwcm9jZXNvcyBtw6FzIHNvZmlzdGljYWRvcyBwYXJhIG1lam9yYXIgbGEgcHJlY2lzacOzbiBlbiBudWVzdHJhcyBwcmVkaWNjaW9uZXMgZGUgZGVtYW5kYS4KICAgIC0gICBMYSBhZGFwdGFiaWxpZGFkIHkgbGEgY2FwYWNpZGFkIGRlIHJlc3BvbmRlciByw6FwaWRhbWVudGUgYSBsb3MgY2FtYmlvcyBlbiBlbCBtZXJjYWRvIHNvbiBmdW5kYW1lbnRhbGVzIHBhcmEgbWFudGVuZXIgbnVlc3RyYSBjb21wZXRpdGl2aWRhZC4KCiMjIEFuw6FsaXNpcyBEZXNjcmlwdGl2byBkZSBsb3MgRGF0b3MKCkEgcGFydGlyIGRlIGxhcyBkaWZlcmVudGVzIGJhc2VzIGRlIGRhdG9zIGNvbXBhcnRpZGFzIHBvciBsYSBlbXByZXNhIEZPUk0geSBsYXMgaW5kdXN0cmlhcyByZWxhY2lvbmFkYXMgY29uIGRpY2hhIGVtcHJlc2EsIHNlbGVjY2lvbmFyIGFsIG1lbm9zIDEgc2l0dWFjacOzbiBwcm9ibGVtYSB5IGVsYWJvcmFyIGxvIHNpZ3VpZW50ZToKCiMjIExpYnJlcsOtYXMgbmVjZXNhcmlhcwoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShpbXB1dGVUUykKbGlicmFyeSh4dHMpCmxpYnJhcnkoem9vKQpsaWJyYXJ5KHRzZXJpZXMpCmxpYnJhcnkoc3RhdHMpCmxpYnJhcnkoZm9yZWNhc3QpCmxpYnJhcnkoYXN0c2EpCmxpYnJhcnkoY29ycnBsb3QpCmxpYnJhcnkod29yZGNsb3VkKQpsaWJyYXJ5KHRpZHl0ZXh0KQpsaWJyYXJ5KEFFUikKbGlicmFyeSh2YXJzKQpsaWJyYXJ5KGR5bmxtKQpsaWJyYXJ5KG1GaWx0ZXIpCmxpYnJhcnkoVFNzdHVkaW8pCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNhcmltYSkKbGlicmFyeShyZWFkcikKbGlicmFyeShyZWFkeGwpCmxpYnJhcnkoaGVhdG1hcGx5KQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocHN5Y2gpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkocmVhZHRleHQpCmxpYnJhcnkoc3l1emhldCkKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkodG0pCmxpYnJhcnkoY2FyZXQpCmxpYnJhcnkoTUFTUykKbGlicmFyeShycGFydCkKbGlicmFyeShycGFydC5wbG90KQpsaWJyYXJ5KHBhcnR5KQpsaWJyYXJ5KGdtb2RlbHMpCmxpYnJhcnkoa25pdHIpCmxpYnJhcnkoY2x1c3RlcikgICAgCmxpYnJhcnkoZTEwNzEpCmxpYnJhcnkocFJPQykKbGlicmFyeShJU0xSKQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShjYXIpCmxpYnJhcnkoRGF0YUV4cGxvcmVyKQpsaWJyYXJ5KHJhbmRvbUZvcmVzdCkKbGlicmFyeShjbGFzcykKbGlicmFyeShmYWN0b2V4dHJhKQpsaWJyYXJ5KHB1cnJyKQpgYGAKCiMjIFByZWd1bnRhcyBkZSBBbsOhbGlzaXMKCkVsYWJvcmFyIDQtNiBwcmVndW50YXMgcmVsYWNpb25hZGFzIGNvbiBsYSBzaXR1YWNpw7NuIHByb2JsZW1hIHNlbGVjY2lvbmFkYSBxdWUgc2UgcHVlZGFuIHJlc3BvbmRlciBtZWRpYW50ZSBlbCBhbsOhbGlzaXMgZGUgZGF0b3MuCgoqKlNpdHVhY2nDs24gUHJvYmxlbWEgMTogUm90YWNpw7NuIGRlIFBlcnNvbmFsKioKLSDCv1F1w6kgZXN0w6EgY2F1c2FuZG8gbGEgcm90YWNpw7NuIGRlIHBlcnNvbmFsIHRhbiBhbHRhPwotIMK/RXhpc3RlIGFsZ8O6biBtb21lbnRvIGRlbCBhw7FvIGRvbmRlIHNlIGRlbiBtw6FzIGJhamFzIGRlbnRybyBkZSBsYSBlbXByZXNhPwotIMK/Q8OzbW8gc2Ugc2llbnRlIGxhIGdlbnRlIGRlbnRybyBkZSBzdSB0cmFiYWpvIGFjdHVhbD8KLSDCv1F1w6kgZmFjdG9yIGF5dWRhIGEgcXVlIGVsIHBlcnNvbmFsIGR1cmUgbcOhcyB0aWVtcG8gZGVudHJvIGRlIGxhIGVtcHJlc2E/Ci0gwr9FbiBxdcOpIHBhcnRlIGRlIGxhIGVtcHJlc2EgZWwgdHJhYmFqYWRvciBzZSBzaWVudGUgbcOhcyBpbmNvbmZvcm1lIHkgY3XDoWwgZXMgc3UgcGVyZmlsPwoKKipTaXR1YWNpw7NuIFByb2JsZW1hIDI6IFByZWRpY2Npw7NuIGRlIERlbWFuZGEqKgotIMK/Q3XDoWxlcyBzb24gbG9zIHBhdHJvbmVzIGhpc3TDs3JpY29zIGRlIGRlbWFuZGEgZGUgZW1wYXF1ZXMgZGUgY2FydMOzbiBwYXJhIGF1dG9wYXJ0ZXMgZW4gbG9zIG1lcmNhZG9zIG9iamV0aXZvIGRlIGxhIGVtcHJlc2EgRk9STSwgeSBjw7NtbyB2YXLDrWFuIGVzdG9zIHBhdHJvbmVzIHNlZ8O6biBsYSB0ZW1wb3JhZGEsIGVsIHRpcG8gZGUgYXV0b3BhcnRlLCB5IGxhcyByZWdpb25lcyBnZW9ncsOhZmljYXM/Ci0g4oGgwr9Dw7NtbyBpbXBhY3RhbiBsb3MgbGFuemFtaWVudG9zIGRlIG51ZXZvcyBtb2RlbG9zIGRlIHZlaMOtY3Vsb3MgeSBsYXMgdGVuZGVuY2lhcyBlbiBsYSBpbmR1c3RyaWEgYXV0b21vdHJpeiBlbiBsYSBkZW1hbmRhIGRlIGRpZmVyZW50ZXMgdGlwb3MgZGUgZW1wYXF1ZXMgZGUgY2FydMOzbiBwYXJhIGF1dG9wYXJ0ZXM/Ci0g4oGgwr9DdcOhbCBoYSBzaWRvIGVsIGVmZWN0byBkZSBsYXMgY2FtcGHDsWFzIGRlIG1hcmtldGluZyB5IGxhcyBhY3RpdmlkYWRlcyBwcm9tb2Npb25hbGVzIGRlIGxhIGVtcHJlc2EgRk9STSBzb2JyZSBsYSBkZW1hbmRhIGRlIHN1cyBwcm9kdWN0b3MgZW4gZWwgcGFzYWRvPwotIOKBoMK/Q8OzbW8gaW1wYWN0YW4gYWxndW5hcyB2YXJpYWJsZXMgZXh0ZXJuYXMgZGUgY2Fyw6FjdGVyIG1hY3JvZWNvbsOzbWljbyBhIGxhcyB2ZW50YXMgZGUgbGEgZW1wcmVzYT8KCiMjIFByb25vc3RpY29zIHkgTmVhcnNob3JpbmcKCi0gKipNZWRpYW50ZSBlbCB1c28gZGUgdmlzdWFsaXphY2nDs24gZGUgZGF0b3MgZGVzY3JpYmlyIGVsIHBvc2libGUgaW1wYWN0byBkZWwgZmVuw7NtZW5vIG5lYXJzaG9yaW5nIHNvYnJlIGVsIGRlc2VtcGXDsW8gZGUgbGEgZW1wcmVzYSBGT1JNLioqCgpFbiB1biBtdW5kbyBlbXByZXNhcmlhbCBjYWRhIHZleiBtw6FzIGdsb2JhbGl6YWRvIHkgY29tcGV0aXRpdm8sIGxhcyBvcmdhbml6YWNpb25lcyBidXNjYW4gY29uc3RhbnRlbWVudGUgZXN0cmF0ZWdpYXMgaW5ub3ZhZG9yYXMgcGFyYSBvcHRpbWl6YXIgc3VzIG9wZXJhY2lvbmVzIHkgbWFudGVuZXJzZSBhIGxhIHZhbmd1YXJkaWEgZGUgc3VzIHJlc3BlY3RpdmFzIGluZHVzdHJpYXMuIFVuYSBkZSBlc3RhcyBlc3RyYXRlZ2lhcyBxdWUgaGEgZ2FuYWRvIHByb3RhZ29uaXNtbyBlbiBsb3Mgw7psdGltb3MgYcOxb3MgZXMgZWwg4oCcTmVhcnNob3JpbmfigJ0sIHVuIGVuZm9xdWUgZGUgb3V0c291cmNpbmcgcXVlIGNvbnNpc3RlIGVuIGRlbGVnYXIgYWN0aXZpZGFkZXMgeSBzZXJ2aWNpb3MgYSBwcm92ZWVkb3JlcyB1YmljYWRvcyBlbiBwYcOtc2VzIGdlb2dyw6FmaWNhbWVudGUgY2VyY2Fub3MuIEVuIGVzdGUgY29udGV4dG8sIE3DqXhpY28gZW1lcmdlIGNvbW8gdW4gZGVzdGlubyBhdHJhY3Rpdm8gcGFyYSBlbCDigJxOZWFyc2hvcmluZ+KAnSwgZ3JhY2lhcyBhIHN1IHViaWNhY2nDs24gZXN0cmF0w6lnaWNhLCByZWN1cnNvIGh1bWFubyBjYXBhY2l0YWRvIHkgY29uZGljaW9uZXMgZWNvbsOzbWljYXMgZmF2b3JhYmxlcy4KCk3DqXhpY28gdGllbmUgdW5hIHViaWNhY2nDs24gZ2VvZ3LDoWZpY2EgcHJpdmlsZWdpYWRhLCBjb21wYXJ0aWVuZG8gZnJvbnRlcmFzIGNvbiBFc3RhZG9zIFVuaWRvcyB5IHNpZW5kbyBwYXJ0ZSBkZWwgVHJhdGFkbyBkZSBMaWJyZSBDb21lcmNpbyBkZSBBbcOpcmljYSBkZWwgTm9ydGUgKFRMQ0FOKSwgaG95IFQtTUVDLCBsbyBxdWUgZmFjaWxpdGEgZWwgYWNjZXNvIGEgdW5vIGRlIGxvcyBtZXJjYWRvcyBtw6FzIGdyYW5kZXMgeSBkaW7DoW1pY29zLiBkZWwgbXVuZG8uIEVzdGEgcHJveGltaWRhZCBnZW9ncsOhZmljYSBubyBzw7NsbyByZWR1Y2UgbG9zIGNvc3RvcyB5IHRpZW1wb3MgZGUgdHJhbnNwb3J0ZSwgc2lubyBxdWUgdGFtYmnDqW4gZmFjaWxpdGEgbGEgY29tdW5pY2FjacOzbiB5IGNvbGFib3JhY2nDs24gZW4gdGllbXBvIHJlYWwgZW50cmUgbGFzIGVtcHJlc2FzIG1hdHJpY2VzIHkgc3VzIHNvY2lvcyBkZSBuZWFyc2hvcmluZy4gQWRlbcOhcywgTcOpeGljbyBoYSBlc3RhYmxlY2lkbyB1bmEgcmVkIGRlIGFjdWVyZG9zIGNvbWVyY2lhbGVzIHF1ZSBicmluZGFuIHZlbnRhamFzIGFyYW5jZWxhcmlhcyB5IGZhY2lsaXRhbiBlbCBmbHVqbyBkZSBiaWVuZXMsIGJyaW5kYW5kbyB1bmEgcGxhdGFmb3JtYSBhdHJhY3RpdmEgcGFyYSBvcGVyYWNpb25lcyBkZSBzdWJjb250cmF0YWNpw7NuLgoKRWwgcGHDrXMgdGFtYmnDqW4gY3VlbnRhIGNvbiB1bmEgZnVlcnphIGxhYm9yYWwgYWx0YW1lbnRlIGNhbGlmaWNhZGEgeSBkaXZlcnNpZmljYWRhLCBxdWUgdmEgZGVzZGUgaW5nZW5pZXJvcyB5IHByb2Zlc2lvbmFsZXMgZGUgdGVjbm9sb2fDrWEgaGFzdGEgZXhwZXJ0b3MgZW4gbWFudWZhY3R1cmEgeSBzZXJ2aWNpb3MgZmluYW5jaWVyb3MuIExvcyBjb3N0b3MgbGFib3JhbGVzIGVuIE3DqXhpY28gc29uIGNvbXBldGl0aXZvcyBlbiBjb21wYXJhY2nDs24gY29uIG90cm9zIGRlc3Rpbm9zIGRlIHN1YmNvbnRyYXRhY2nDs24sIGxvIHF1ZSBwZXJtaXRlIGEgbGFzIGVtcHJlc2FzIG9idGVuZXIgbWF5b3IgdmFsb3IgYWdyZWdhZG8gYSB1biBtZW5vciBjb3N0by4gQWRlbcOhcywgZWwgY29udGludW8gY3JlY2ltaWVudG8gZW4gZWR1Y2FjacOzbiB5IGZvcm1hY2nDs24gaGEgaW1wdWxzYWRvIGxhIGZvcm1hY2nDs24gZGUgcHJvZmVzaW9uYWxlcyBhbHRhbWVudGUgY3VhbGlmaWNhZG9zLCBsbyBxdWUgZ2FyYW50aXphIGxhIGRpc3BvbmliaWxpZGFkIGRlbCB0YWxlbnRvIG5lY2VzYXJpbyBwYXJhIGN1YnJpciBsYXMgZGVtYW5kYXMgZGVsIOKAnE5lYXJzaG9yaW5n4oCdLiBUb2RvIGVzdG8gaGEgaGVjaG8gcXVlIGVuIGxvcyDDumx0aW1vcyBhw7FvcyBNw6l4aWNvIGhheWEgc2lkbyB0ZXN0aWdvIGRlbCBhY2VsZXJhZG8gcHJvY2VzbyBkZSBOZWFyc2hvcmluZywgZG9uZGUgbXVjaGFzIGVtcHJlc2FzIGludGVybmFjaW9uYWxlcyBoYW4gZGVjaWRpZG8gaW52ZXJ0aXIgZW4gbnVlc3RybyBwYcOtcyBwYXJhIGFicmlyIG1lZ2Fmw6FicmljYXMuIFJlY2llbnRlbWVudGUgZGVzdGFjYSBlbCBjYXNvIGRlIFRlc3RhIHkgc3UgZ2lnYWbDoWJyaWNhIGVuIGVsIGVzdGFkbyBkZSBOdWV2byBMZcOzbi4gLiBFc3RlIGZlbsOzbWVubyBwb2Ryw61hIHRyYWVyIGdyYW5kZXMgYmVuZWZpY2lvcyBhIG51ZXN0cm8gcGHDrXMgcG9yIHRvZGFzIGxhcyBww6lyZGlkYXMgZWNvbsOzbWljYXMgcXVlIGNvbmxsZXZhLiBTZWfDum4gZWwgR2xvYmFsIEJ1c2luZXNzIENvdW5jaWwgKENFRykgKDIwMjMpLCBlbCBuZWFyc2hvcmluZyBwb2Ryw61hIGdlbmVyYXIgaGFzdGEgNCBtaWxsb25lcyBkZSBlbXBsZW9zIGVuIHRlcnJpdG9yaW8gbWV4aWNhbm8gcGFyYSAyMDMwLCByZWNpYmllbmRvIGVudHJlIDMwIHkgNTAgbWlsIG1pbGxvbmVzIGRlIGTDs2xhcmVzIGFudWFsZXMsIGFkZW3DoXMsIGVsIG1pc21vIGVzdHVkaW8gc2XDsWFsYSBxdWUgZXN0ZSBmZW7Ds21lbm8gcHVlZGUgc2VyIHJlc3BvbnNhYmxlIGRlIGF1bWVudGFuZG8gZWwgUElCIGRlIE3DqXhpY28gaGFzdGEgZW4gdW4gMi41JSBlbiBsb3MgcHLDs3hpbW9zIDYgYcOxb3MuIFBvciBsbyB0YW50bywgZXMgbXV5IGltcG9ydGFudGUgYW5hbGl6YXIgeSBjb21wcmVuZGVyIGVzdGUgZmVuw7NtZW5vIGEgdHJhdsOpcyBkZWwgYW7DoWxpc2lzIGVzdGFkw61zdGljbyBkZSBkYXRvcyBoaXN0w7NyaWNvcyBkZSBJbnZlcnNpw7NuIEV4dHJhbmplcmEgRGlyZWN0YSB5IGFsZ3VuYXMgdmFyaWFibGVzIG1hY3JvZWNvbsOzbWljYXMgcXVlIGVzdMOhbiBlc3RyZWNoYW1lbnRlIHJlbGFjaW9uYWRhcyBjb24gZGljaGEgdmFyaWFibGUgZGVwZW5kaWVudGUuCgojIyMgUHJvbm9zdGljYXIgZWwgZXZlbnRvIGRlIE5lYXJzaG9yaW5nLgoKIyMjIyBCYXNlcyBkZSBEYXRvcyBkZSBOZWFyc2hvcmluZwpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpzZXR3ZCgiLi4vZGF0YWJhc2VzL25lYXJzaG9yaW5nIikKZGY9cmVhZC5jc3YoInF1YXJ0ZXJfZWNvbm9taWNfZGF0YS5jc3YiKQoKc3VtbWFyeShkZikKYGBgCgpgYGB7cn0Kc3RyKGRmKQpgYGAKCmBgYHtyfQojIENhbGN1bGFtb3MgZWwgbsO6bWVybyBkZSBOQSBwb3IgY29sdW1uYQpuYXNfcG9yX2NvbHVtbmEgPC0gc2FwcGx5KGRmLCBmdW5jdGlvbih4KSBzdW0oaXMubmEoeCkpKQoKIyBGaWx0cmFtb3MgbGFzIGNvbHVtbmFzIHF1ZSB0aWVuZW4gNyBvIG3DoXMgTkEgcGFyYSBlbGltaW5hcmxhcwpjb2x1bW5hc19wYXJhX2VsaW1pbmFyIDwtIG5hbWVzKG5hc19wb3JfY29sdW1uYVtuYXNfcG9yX2NvbHVtbmEgPj0gN10pCmRmIDwtIGRmICU+JSBzZWxlY3QoLW9uZV9vZihjb2x1bW5hc19wYXJhX2VsaW1pbmFyKSkKCiMgUGFyYSBsYXMgY29sdW1uYXMgcmVzdGFudGVzLCBpbXB1dGFtb3MgbG9zIE5BIGNvbiBsYSBtZWRpYW5hCmRmIDwtIGRmICU+JSBtdXRhdGUoYWNyb3NzKC5jb2xzID0gd2hlcmUofiBzdW0oaXMubmEoLikpIDwgNyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAuZm5zID0gfiBpZmVsc2UoaXMubmEoLiksIG1lZGlhbiguLCBuYS5ybSA9IFRSVUUpLCAuKSkpCmBgYAoKU2UgcmVhbGl6w7MgdW5hIGltcHV0YWNpw7NuIGRlIGxhcyB2YXJpYWJsZXMgeSBzZSBlbGltaW5hcm9uIGFxdWVsbGFzIGNvbiBkZW1hc2lhZG9zIHZhbG9yZXMgTkFTIGZhbHRhbnRlcy4gCgoqKkFuYWxpc2lzIGRlIGxhIEJhc2UgZGUgTmVhcnNob3JpbmcqKgoKYGBge3J9CnN1bW1hcnkoZGYpCmBgYAoKYGBge3J9CmRhdGFmPWRmCgpkYXRhMiA8LSBkZiAlPiUgc2VsZWN0KFllYXIsIFF1YXJ0ZXIsIE5ld19GRElfSW5mbG93cykKZGF0YTIkRmVjaGEgPC0gYXMuRGF0ZShwYXN0ZShkYXRhMiRZZWFyLCBkYXRhMiRRdWFydGVyKSwgZm9ybWF0ID0gIiVZICVCIikKCnRpbWVfc2VyaWUgPC0gdHMoZGF0YTIkTmV3X0ZESV9JbmZsb3dzLCBzdGFydCA9IGMoMjAwNiwgMSksIGZyZXF1ZW5jeSA9IDQpCgpwcmludCh0aW1lX3NlcmllKQpgYGAKClNlIGNvbnZpcnRpw7MgbGEgdmFyaWFibGUgZGUgQcOxbyBlbiBlbCBmb3JtYXRvIGFkZWN1YWRvIGRlIGZlY2hhLgoKYGBge3J9CnBsb3QodGltZV9zZXJpZSwgbWFpbiA9ICJJRUQgcXVhcnRlciIsIHhsYWIgPSAiWWVhciBxdWFydGVyIiwgeWxhYiA9ICJJRUQiKQpgYGAKUG9kZW1vcyB2ZXIgcXVlIGVsIGdyw6FmaWNvIHByZXNlbnRhIHVuIGNsYXJvIGNvbXBvbmVudGUgZGUgZXN0YWNpb25hbGlkYWQgeSBwdWVkZSBoYWJlciBjaWVydGEgZXN0YWNpb25hcmllZGFkLCBzaW4gZW1iYXJnbywgc2UgdmUgdW5hIHRlbmRlbmNpYSBhc2NlbmRlbnRlIGEgbG8gbGFyZ28gZGUgdG9kYSBsYSBzZXJpZSBkZSB0aWVtcG8sIHBvciBsbyBxdWUgZXMgbmVjZXNhcmlvIGFwbGljYXIgZGl2ZXJzYXMgcHJ1ZWJhcyBwYXJhIGNvbXByZW5kZXIgbWVqb3IgbnVlc3RyYSBzZXJpZSBkZSB0aWVtcG8uCgpgYGB7cn0KZGVzY29tcG9zZTwtZGVjb21wb3NlKHRpbWVfc2VyaWUpCnBsb3QoZGVzY29tcG9zZSkKYGBgCgpFbiBlbCBncsOhZmljbyBhbnRlcmlvciBwb2RlbW9zIG9ic2VydmFyIHVuYSBsaWdlcmEgdGVuZGVuY2lhIGVuIHRvZGEgbGEgc2VyaWUgdGVtcG9yYWwgY29tbyBzZSBkZXNjcmliacOzIGFudGVyaW9ybWVudGUsIGVzdG8gcG9kcsOtYSBhZmVjdGFyIGxhIHByZXNlbmNpYSBkZSBlc3RhY2lvbmFyaWVkYWQuIFBvciBvdHJvIGxhZG8sIHNlIGV2aWRlbmNpYSBlbCBjb21wb25lbnRlIGVzdGFjaW9uYWwsIHF1ZSBhdW1lbnRhIGVuIGFsZ3Vub3MgdHJpbWVzdHJlcyBkZSBjYWRhIHBlcsOtb2RvLiBFc3RvIHNlIHB1ZWRlIGV4cGxpY2FyIGVuIGVsIGNvbnRleHRvIGRlIGxhIHZhcmlhYmxlIGRlcGVuZGllbnRlIGNvbiBlc3RhY2lvbmFsaWRhZGVzIGVuIGxhIGRlbWFuZGEgZGUgYmllbmVzIHkgc2VydmljaW9zLCBldmVudG9zIGVjb27Ds21pY29zIGNvbW8gZmVyaWFzIGNvbWVyY2lhbGVzIG8gdGVtcG9yYWRhcyBkZSBpbXB1ZXN0b3MuICwgbyBpbmNsdXNvIHBhdHJvbmVzIGVzdGFjaW9uYWxlcyBlbiBsYSBkaXNwb25pYmlsaWRhZCBkZSByZWN1cnNvcyBuYXR1cmFsZXMuIAoKVG9kbyBlc3RvIGhhY2UgcXVlIGVuIGFsZ3VuYXMgcGFydGVzIGRlIGNhZGEgYcOxbyBsYSBJRUQgYXVtZW50ZSB5IGRpc21pbnV5YSBwZXJpw7NkaWNhbWVudGUuIFJlc3BlY3RvIGFsIGNvbXBvbmVudGUgYWxlYXRvcmlvIHJlc2lkdWFsLCBzZSBvYnNlcnZhIGNpZXJ0byBydWlkbyBlbiBsYXMgc2VyaWVzIHRlbXBvcmFsZXMsIGVzcGVjaWFsbWVudGUgZW4gZWwgcGVyw61vZG8gMjAxMy0yMDE1IHkgMjAyMCBhIDIwMjIuIEVzdG8gc2UgZGViZSBhIHZhcmlhY2lvbmVzIGVuIGxhIHNlcmllIHRlbXBvcmFsIHF1ZSBubyBwdWVkZW4gZXhwbGljYXJzZSBjb24gY29tcG9uZW50ZXMgZGUgZXN0YWNpb25hbGlkYWQgbyB0ZW5kZW5jaWFzIGVuIGxhIHNlcmllIHRlbXBvcmFsLiBFc3RvLCBlbiB1biBjb250ZXh0byByZWFsLCBzZSBwdWVkZSBleHBsaWNhciBjb24gZmVuw7NtZW5vcyBjb24gbGFzIHJlZm9ybWFzIGNvbnN0aXR1Y2lvbmFsZXMgZGVsIHByZXNpZGVudGUgRW5yaXF1ZSBQZcOxYSBOaWV0byBlbiAyMDEzIHkgbGEgcGFuZGVtaWEgZGUgQ09WSUQtMTkgYSBwYXJ0aXIgZGUgMjAyMC4KCmBgYHtyIHdhcm5pbmc9RkFMU0V9CiMgVGhlIHN0YXRpb25hcml0eSBvZiB0aGUgc2VyaWVzIGlzIGNoZWNrZWQgd2l0aCB0aGUgZm9sbG93aW5nIEFERiB0ZXN0LgphZGYudGVzdCh0aW1lX3NlcmllKQpgYGAKRWwgcmVzdWx0YWRvIGRlIGxhIFBydWViYSBBdW1lbnRhZGEgZGUgRGlja2V5LUZ1bGxlciAoQURGKSBjb24gdW4gdmFsb3IgcCBkZSAwLjAxIChtZW5vciBhIDAuMDUpIGluZGljYSBxdWUgbGEgc2VyaWUgdGVtcG9yYWwg4oCcdGltZV9zZXJpZXPigJ0gZXMgZXN0YWNpb25hcmlhLCBsbyBxdWUgc2lnbmlmaWNhIHF1ZSBubyBtdWVzdHJhIHRlbmRlbmNpYXMgZW4gZWwgdGllbXBvLgoKYGBge3J9CmFjZih0aW1lX3NlcmllLG1haW49IlNpZ25pZmljYW50IEF1dG9jb3JyZWxhdGlvbnMiKSAKYGBgCgpQb2RlbW9zIG9ic2VydmFyIHF1ZSBsYSBzZXJpZSBubyBtdWVzdHJhIGRlIGF1dG9jb3JyZWxhY2nDs24gc2VyaWFsLCB5YSBxdWUgZW4gbG9zIHBlcmlvZG9zIGxhIGZ1bmNpw7NuIGRlIGF1dG9jb3JyZWxhY2nDs24gbm8gZXhjZWRlIGxhcyBsw61uZWFzIGRlIHNpZ25pZmljYW5jaWEuCgojIyMjIE1vZGVsbyBBcm1hIENhbGN1bGFkbwoKYGBge3Igd2FybmluZz1GQUxTRX0Kc3VtbWFyeShhcm1hPC1hcm1hKGRpZmYodGltZV9zZXJpZSkpLG9yZGVyPWMoMSwxKSkKcGxvdChhcm1hKQpgYGAKRXN0b3MgY29lZmljaWVudGVzIGluZGljYW4gdW5hIGNvcnJlbGFjacOzbiBwb3NpdGl2YSBkw6liaWwgY29uIGVsIHZhbG9yIGFudGVyaW9yIHkgdW5hIGNvcnJlbGFjacOzbiBuZWdhdGl2YSBmdWVydGUgY29uIGVsIGVycm9yIGVuIGVsIHBlcsOtb2RvIGFudGVyaW9yLCByZXNwZWN0aXZhbWVudGUuIEFkZW3DoXMsIHNlIGhhIGluY2x1aWRvIHVuIHTDqXJtaW5vIGRlIGludGVyY2VwdGFjacOzbiBjb24gdW4gdmFsb3IgZXN0aW1hZG8gZGUgMTA5LjgwNTAKCkxvcyByZXNpZHVvcyBkZWwgbW9kZWxvIHRpZW5lbiB1bmEgdmFyaWFuemEgZXN0aW1hZGEgKHNpZ21hXjIpIGRlIDQ3NzQ0ODUgeSBsb3MgcmVzdWx0YWRvcyBkZWwgYWp1c3RlIG11ZXN0cmFuIHVuIEFJQyBtdXkgYWx0by4KCiMjIyMgTW9kZWxvIEFyaW1hIGNvbiBMb2cgeSBEaWZmIENhbGN1bGFkbwoKYGBge3Igd2FybmluZz1GQUxTRX0Kc3VtbWFyeShhcmltYTwtQXJpbWEoZGlmZihsb2coKHRpbWVfc2VyaWUpKSksb3JkZXI9YygxLDEsMSkpKSAKcGxvdChhcmltYSkKYGBgCgpFbCBjb2VmaWNpZW50ZSBhdXRvcnJlZ3Jlc2l2byAoQVIxKSBlcyAtMCw2OTc3IHkgZWwgY29lZmljaWVudGUgZGUgbWVkaWEgbcOzdmlsIChNQTEpIGVzIC0xLDAwMDAuIEVzdG9zIGNvZWZpY2llbnRlcyBpbmRpY2FuIHF1ZSBlbCB2YWxvciBhY3R1YWwgZGUgbGEgc2VyaWUgdGVtcG9yYWwgbG9nYXLDrXRtaWNhbWVudGUgZGlmZXJlbmNpYWRhIGVzdMOhIGNvcnJlbGFjaW9uYWRvIG5lZ2F0aXZhbWVudGUgY29uIHN1IHZhbG9yIGFudGVyaW9yIHkgY29uIGVsIGVycm9yIGVuIGVsIHBlcsOtb2RvIGFudGVyaW9yLgoKTGEgdmFyaWFuemEgZXN0aW1hZGEgZGVsIG1vZGVsbyAoc2lnbWFeMikgZXMgMCwwLjU2NTUuIEVsIHZhbG9yIGxvZ2Fyw610bWljbyBkZSB2ZXJvc2ltaWxpdHVkIGVzIC03My44OSwgeSBsb3MgY3JpdGVyaW9zIGRlIGluZm9ybWFjacOzbiwgY29tbyBlbCBBSUMgKEFrYWlrZSBJbmZvcm1hdGlvbiBDcml0ZXJpb24pLCBlbCBBSUMgY29ycmVnaWRvIChBSUNjKSB5IGVsIEJJQyAoQmF5ZXNpYW4gSW5mb3JtYXRpb24gQ3JpdGVyaW9uKSwgaW5kaWNhbiBxdWUgZXN0ZSBtb2RlbG8gcG9kcsOtYSBzZXIgYXByb3BpYWRvIHBhcmEgbGEgc2VyaWUgdGVtcG9yYWwuCgojIyMjIFBydWViYXMgZGUgRGlhZ25vc3RpY28gZW4gbGEgRGF0YQoKKipNb2RlbG8gQXJtYSoqCmBgYHtyfQphcm1hX3Jlc2lkdWFsczwtYXJtYSRyZXNpZHVhbHMKQm94LnRlc3QoYXJtYV9yZXNpZHVhbHMsbGFnPTEsdHlwZT0iTGp1bmctQm94IikKYGBgCgpFbCB2YWxvciBkZSBwIG9idGVuaWRvIGVuIGxhIHBydWViYSBkZSBCb3gtTGp1bmcgKDAsMDcpIGVzIG1heW9yIHF1ZSBlbCB2YWxvciBkZSBwIG3DoXhpbW8gY29tw7pubWVudGUgdXRpbGl6YWRvIHF1ZSBlcyAwLDA1LiBFc3RvIHNpZ25pZmljYSBxdWUgbm8gc2UgZW5jb250csOzIGV2aWRlbmNpYSBzaWduaWZpY2F0aXZhIGRlIGF1dG9jb3JyZWxhY2nDs24gZW4gbG9zIHJlc2lkdW9zLCB5YSBxdWUgZWwgdmFsb3IgcCBlcyBtYXlvciBxdWUgMCwwNSwgbG8gcXVlIHJlc3BhbGRhIGxhIHZhbGlkZXogZGVsIG1vZGVsbyBlbiB0w6lybWlub3MgZGUgYXV0b2NvcnJlbGFjacOzbi4KCmBgYHtyfQojVGVzdGluZyByZXNpZHVhbHMKc3VwcHJlc3NXYXJuaW5ncyh7CmFybWEkcmVzaWR1YWxzIDwtIG5hLm9taXQoYXJtYSRyZXNpZHVhbHMpCmFkZi50ZXN0KGFybWEkcmVzaWR1YWxzKQp9KQpgYGAKRWwgdmFsb3IgZGUgcCBkZSAwLDAxLCBpbmZlcmlvciBhbCB1bWJyYWwgZGUgMCwwNSwgaW5kaWNhIHVuYSBmdWVydGUgZXZpZGVuY2lhIGNvbnRyYSBsYSBoaXDDs3Rlc2lzIG51bGEgZGUgbm8gZXN0YWNpb25hcmllZGFkLiBFc3RvIHNpZ25pZmljYSBxdWUgZXMgcG9jbyBwcm9iYWJsZSBxdWUgbG9zIHJlc2lkdW9zIHNlYW4gbm8gZXN0YWNpb25hcmlvcy4KCgpgYGB7cn0KaGlzdChhcm1hJHJlc2lkdWFscykKYGBgClNlIGFwcmVjaWEgcmVsYXRpdmEgbm9ybWFsaWRhZCBlbiBsb3MgcmVzaWR1YWxlcy4KCioqTW9kZWxvIEFyaW1hKioKYGBge3J9CmFyaW1hX3Jlc2lkdWFsczwtYXJpbWEkcmVzaWR1YWxzCkJveC50ZXN0KGFyaW1hX3Jlc2lkdWFscyxsYWc9MSx0eXBlPSJManVuZy1Cb3giKQpgYGAKCkVsIHZhbG9yIGRlIHAgb2J0ZW5pZG8gZW4gbGEgcHJ1ZWJhIGRlIEJveC1ManVuZyAoMCw4KSBlcyBtYXlvciBxdWUgZWwgdmFsb3IgZGUgcCBtw6F4aW1vIGNvbcO6bm1lbnRlIHV0aWxpemFkbyBxdWUgZXMgMCwwNS4gRXN0byBzaWduaWZpY2EgcXVlIG5vIHNlIGVuY29udHLDsyBldmlkZW5jaWEgc2lnbmlmaWNhdGl2YSBkZSBhdXRvY29ycmVsYWNpw7NuIGVuIGxvcyByZXNpZHVvcywgeWEgcXVlIGVsIHZhbG9yIHAgZXMgbWF5b3IgcXVlIDAsMDUsIGxvIHF1ZSByZXNwYWxkYSBsYSB2YWxpZGV6IGRlbCBtb2RlbG8gZW4gdMOpcm1pbm9zIGRlIGF1dG9jb3JyZWxhY2nDs24uCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpyZXNpZHVhbHNfdHMgPC0gYXJpbWEkcmVzaWR1YWxzCgojIEludGVycG9sYXIgbG9zIHZhbG9yZXMgTkEKcmVzaWR1YWxzX2NsZWFuIDwtIG5hLmFwcHJveChyZXNpZHVhbHNfdHMpCgpzdXBwcmVzc1dhcm5pbmdzKHsKICBhZGZfdGVzdF9yZXN1bHQgPC0gYWRmLnRlc3QocmVzaWR1YWxzX2NsZWFuKQp9KQoKIyBWZXIgZWwgcmVzdWx0YWRvCnByaW50KGFkZl90ZXN0X3Jlc3VsdCkKYGBgCkVsIHZhbG9yIGRlIHAgZGUgMCwwMSwgaW5mZXJpb3IgYWwgdW1icmFsIGRlIDAsMDUsIGluZGljYSB1bmEgZnVlcnRlIGV2aWRlbmNpYSBjb250cmEgbGEgaGlww7N0ZXNpcyBudWxhIGRlIG5vIGVzdGFjaW9uYXJpZWRhZC4gRXN0byBzaWduaWZpY2EgcXVlIGVzIHBvY28gcHJvYmFibGUgcXVlIGxvcyByZXNpZHVvcyBzZWFuIG5vIGVzdGFjaW9uYXJpb3MuCgpgYGB7cn0KaGlzdChhcmltYSRyZXNpZHVhbHMpCmBgYAoKU2UgYXByZWNpYSBub3JtYWxpZGFkIGVuIGxvcyByZXNpZHVhbGVzIGRlbCBtb2RlbG8gMi4KCkRlYmlkbyBhIG3DqXRyaWNhcyBjb21vIGVsIEFJQyB5IGEgbGFzIHBydWViYXMgZGUgZGlhZ27Ds3N0aWNvLCBlbCBtb2RlbG8gMiBlcyBlbGVnaWRvIGNvbW8gZWwgbcOhcyBhcHJvcGlhZG8uCgojIyMjIEZvcmVjYXN0IGRlIE5lYXJzaG9yaW5nCgpgYGB7cn0Kc3VwcHJlc3NXYXJuaW5ncyh7CmFyaW1hX3Jlc3RhdXJhY2lvbjwtZXhwKGFyaW1hJGZpdHRlZCkgIyBUaGUgdmFyaWFibGVzIGFyZSB0cmFuc2Zvcm1lZCBiYWNrIHRvIHRoZSBvcmlnaW5hbHMgKGlmIGxvZyBpcyBhcHBsaWVkLCB0aGUgZXhwb25lbnRpYWwgbXVzdCBiZSBhcHBsaWVkIChpdCBpcyB0aGUgb3Bwb3NpdGUpKQp2ZWN0b3IyID1jKGFyaW1hX3Jlc3RhdXJhY2lvbikgI3JldmVydGluZyAibG9nIiBvcGVyYXRpb24gdXNpbmcgImV4cCIKb3JpZ2luYWwyIDwtYyh0aW1lX3NlcmllKSAjQ29udmVydGluZyBpbnRvIGEgdmVjdG9yLgpyZXN0YXVyYWNpb24yID0gdmVjdG9yMitvcmlnaW5hbDIgI3JldmVydGluZyAiZGlmZiIgb3BlcmF0aW9uIHN1bW1pbmcgdGhlIG9yaWdpbmFsIHZhbHVlcyB0byB0aGUgZGlmZmVyZW5jZXMuCnRzMiA8LSB0cyhyZXN0YXVyYWNpb24yLCBzdGFydCA9IDEsIGVuZCA9IGxlbmd0aChyZXN0YXVyYWNpb24yKSwgZnJlcXVlbmN5ID0gNCkgI01ha2UgdGltZSBzZXJpZXMKfSkKYGBgCgpgYGB7ciB3YXJuaW5nPUZBTFNFfQojIEZvcmVjYXN0IChBUklNQSkKYXJpbWFfZm9yZWNhc3Q8LWZvcmVjYXN0KHRzMixoPTUpCmFyaW1hX2ZvcmVjYXN0CnBsb3QoYXJpbWFfZm9yZWNhc3QpCmF1dG9wbG90KGFyaW1hX2ZvcmVjYXN0KQpgYGAKCkVuIGVsIHByb27Ds3N0aWNvIHJlYWxpemFkbyBwYXJhIGxhIEludmVyc2nDs24gRXh0cmFuamVyYSBEaXJlY3RhIChJRUQpIHJlbGFjaW9uYWRhIGNvbiBlbCBmZW7Ds21lbm8gZGVsIG5lYXJzaG9yaW5nLCBzZSBvYnNlcnZhbiB0ZW5kZW5jaWFzIHkgdmFyaWFjaW9uZXMgaW50ZXJlc2FudGVzIHBhcmEgbG9zIHByw7N4aW1vcyBjaW5jbyB0cmltZXN0cmVzLiBMYSBwcmVkaWNjacOzbiBzZSBwcmVzZW50YSBjb24gaW50ZXJ2YWxvcyBkZSBjb25maWFuemEgZGVsIDgwJSB5IGRlbCA5NSUsIGxvIHF1ZSBub3MgcGVybWl0ZSBlbnRlbmRlciBsYSBpbmNlcnRpZHVtYnJlIGFzb2NpYWRhIGNvbiBjYWRhIGVzdGltYWNpw7NuIGRlIHB1bnRvLgoKUGFyYSBlbCBjdWFydG8gdHJpbWVzdHJlIGRlbCBhw7FvIDI0LCBlbCBwcm9uw7NzdGljbyBkZSBwdW50byBlc3RpbWEgdW5hIElFRCBkZSAzLDAzNi4wNjQgbWlsbG9uZXMgZGUgZMOzbGFyZXMuIExvcyBpbnRlcnZhbG9zIGRlIGNvbmZpYW56YSBzdWdpZXJlbiBxdWUsIGNvbiB1biA4MCUgZGUgY29uZmlhbnphLCBsYSBJRUQgcG9kcsOtYSB2YXJpYXIgZW50cmUgMSwxMjEuOTg2IHkgNCw5NTAuMTQzIG1pbGxvbmVzIGRlIGTDs2xhcmVzLiBBbXBsaWFuZG8gbGEgY2VydGV6YSBhbCA5NSUsIGVsIHJhbmdvIHNlIGV4dGllbmRlIGRlc2RlIDEwOC43MzQgaGFzdGEgNSw5NjMuMzk0IG1pbGxvbmVzIGRlIGTDs2xhcmVzLCBpbmRpY2FuZG8gdW5hIG1heW9yIGluY2VydGlkdW1icmUgZW4gbGFzIGVzdGltYWNpb25lcy4KCkVuIGVsIHByaW1lciB0cmltZXN0cmUgZGVsIGHDsW8gMjUsIHNlIGVzcGVyYSB1biBhdW1lbnRvIGVuIGxhIElFRCBoYXN0YSBsb3MgMyw3NDIuNTQ3IG1pbGxvbmVzIGRlIGTDs2xhcmVzLiBFbCBpbnRlcnZhbG8gZGUgY29uZmlhbnphIGRlbCA4MCUgc2Ugc2l0w7phIGVudHJlIDEsMzgzLjA2OCB5IDYsMTAyLjAyNiBtaWxsb25lcyBkZSBkw7NsYXJlcywgbWllbnRyYXMgcXVlIGVsIGludGVydmFsbyBhbCA5NSUgc2UgYW1wbMOtYSBkZXNkZSAxMzQuMDM2IGhhc3RhIDcsMzUxLjA1OCBtaWxsb25lcyBkZSBkw7NsYXJlcywgcmVmbGVqYW5kbyBudWV2YW1lbnRlIGxhIGluY2VydGlkdW1icmUgZW4gZWwgcHJvbsOzc3RpY28uCgpQYXJhIGVsIHNlZ3VuZG8gdHJpbWVzdHJlIGRlbCBhw7FvIDI1LCBlbCBwcm9uw7NzdGljbyBtdWVzdHJhIHVuYSBkaXNtaW51Y2nDs24gZW4gbGEgSUVEIGEgMiwzMTguNDEyIG1pbGxvbmVzIGRlIGTDs2xhcmVzLiBMb3MgaW50ZXJ2YWxvcyBkZSBjb25maWFuemEgcGFyYSBlc3RlIHRyaW1lc3RyZSBzb24gbcOhcyBlc3RyZWNob3MsIGNvbiBlbCBpbnRlcnZhbG8gZGVsIDgwJSB2YXJpYW5kbyBlbnRyZSA4NTYuNzc1IHkgMyw3ODAuMDQ5IG1pbGxvbmVzIGRlIGTDs2xhcmVzLCB5IGVsIGRlbCA5NSUgZW50cmUgODMuMDMyIHkgNCw1NTMuNzkzIG1pbGxvbmVzIGRlIGTDs2xhcmVzLgoKRW4gZWwgdGVyY2VyIHRyaW1lc3RyZSBkZWwgYcOxbyAyNSwgc2UgcHJldsOpIHVuIHJlcHVudGUgZW4gbGEgSUVEIGEgMywxMjguNjA0IG1pbGxvbmVzIGRlIGTDs2xhcmVzLCBjb24gaW50ZXJ2YWxvcyBkZSBjb25maWFuemEgc2ltaWxhcmVzIGEgbG9zIG9ic2VydmFkb3MgZW4gZWwgY3VhcnRvIHRyaW1lc3RyZSBkZWwgYcOxbyAyNC4KCkZpbmFsbWVudGUsIHBhcmEgZWwgY3VhcnRvIHRyaW1lc3RyZSBkZWwgYcOxbyAyNSwgZWwgcHJvbsOzc3RpY28gdnVlbHZlIGEgZXN0aW1hciB1bmEgSUVEIGRlIDMsMDM2LjA2NCBtaWxsb25lcyBkZSBkw7NsYXJlcywgY29uIGludGVydmFsb3MgZGUgY29uZmlhbnphIHByw6FjdGljYW1lbnRlIGlkw6ludGljb3MgYSBsb3MgZGVsIGN1YXJ0byB0cmltZXN0cmUgZGVsIGHDsW8gMjQuCgpFc3RlIGFuw6FsaXNpcyBkZSBwcm9uw7NzdGljbyBtdWVzdHJhIHVuYSB2YXJpYWJpbGlkYWQgc2lnbmlmaWNhdGl2YSBlbiBsYSBJRUQgZXNwZXJhZGEgcmVsYWNpb25hZGEgY29uIGVsIG5lYXJzaG9yaW5nIGEgbG8gbGFyZ28gZGUgbG9zIHByw7N4aW1vcyBjaW5jbyB0cmltZXN0cmVzLiAKCgojIyMgUHJvbm9zdGljYXIgZWwgZGVzZW1wZcOxbyBkZSBGT1JNCgojIyMjIEJhc2VzIGRlIERhdG9zIGRlIFZlbnRhcwoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI2ZpbGUuY2hvb3NlKCkKc2V0d2QoIi4uL2RhdGFiYXNlcy8iKQp2ZW50YXMxIDwtIHJlYWRfZXhjZWwoImZvcm0vRk9STS1WZW50YXMueGxzeCIpCnZlbnRhczIgPC0gcmVhZF9leGNlbCgiZm9ybS9GT1JNLVZlbnRhcy54bHN4IikKCiMgZGF0YSBkZSBiYXNlcwpuYW1lcyh2ZW50YXMxKQpzdHIodmVudGFzMSkKYGBgCgoqKkFuYWxpc2lzIGRlIE51bWVybyBkZSBEYXRhIEZhbHRhbnRlKioKYGBge3J9CiMgQ2FsY3VsYSB5IG11ZXN0cmEgbGEgY2FudGlkYWQgZGUgdmFsb3JlcyBOQSBwb3IgY29sdW1uYSBlbiB2ZW50YXMxLgpuYV9jb3VudDEgPC0gY29sU3Vtcyhpcy5uYSh2ZW50YXMxKSkKbmFfY291bnQxCgojIEVsaW1pbmEgY29sdW1uYXMgY29uIE5BIGVuIHZlbnRhczEgeSBsYXMgw7psdGltYXMgMyBmaWxhcy4KdmVudGFzMSA8LSB2ZW50YXMxWywgY29sU3Vtcyhpcy5uYSh2ZW50YXMxKSkgPT0gMF0KdmVudGFzMSA8LSBoZWFkKHZlbnRhczEsIC0zKQoKIyBDYWxjdWxhIHkgbXVlc3RyYSBsYSBjYW50aWRhZCBkZSB2YWxvcmVzIE5BIHBvciBjb2x1bW5hIGVuIHZlbnRhczIuCm5hX2NvdW50MiA8LSBjb2xTdW1zKGlzLm5hKHZlbnRhczIpKQpuYV9jb3VudDIKCiMgRWxpbWluYSBmaWxhcyBjb24gTkEgZW4gdmVudGFzMi4KdmVudGFzMiA8LSB2ZW50YXMyW2NvbXBsZXRlLmNhc2VzKHZlbnRhczIpLCBdCgojIFJlbm9tYnJhIGxhIGNvbHVtbmEgIlZlbnRhcyBUb3RhbGVzIiBhICJWZW50YXNfdG90YWxlcyIgZW4gdmVudGFzMS4KbmFtZXModmVudGFzMSlbbmFtZXModmVudGFzMSkgPT0gIlZlbnRhcyBUb3RhbGVzIl0gPC0gIlZlbnRhc190b3RhbGVzIgpgYGAKCk9ic2VydmFtb3MgdW5hIHByZXNlbmNpYSBzaWduaWZpY2F0aXZhIGRlIHZhbG9yZXMgTkEuIFBvciBlbGxvLCBkZWNpZGltb3MgZWxpbWluYXIgbGFzIGNvbHVtbmFzIHF1ZSBjb250ZW5nYW4gdmFsb3JlcyBOQSBlbiBsYSBiYXNlIGRlIGRhdG9zIDEgeSBsYXMgZmlsYXMgY29uIHZhbG9yZXMgTkEgZW4gbGEgYmFzZSBkZSBkYXRvcyAyLgoKYGBge3J9CiN2ZW50YXMxJE1lcyA8LSBhcy55ZWFybW9uKHBhc3RlKHZlbnRhczEkQcOxbywgdmVudGFzMSRNZXMpLCAiJVkgJUIiKQojdmVudGFzMiRNZXMgPC0gYXMueWVhcm1vbihwYXN0ZSh2ZW50YXMyJEHDsW8sIHZlbnRhczIkTWVzKSwgIiVZICVCIikKYGBgCgojIyMjIFBydWViYXMgZGUgRGlhZ25vc3RpY28gZW4gbGEgRGF0YQoKYGBge3J9CnZlbnRhczEkTWVzIDwtIGFzLkRhdGUocGFzdGUodmVudGFzMSRBw7FvLCB2ZW50YXMxJE1lcyksIGZvcm1hdCA9ICIlWSAlQiIpCgpWZW50YXMgPC0gdHModmVudGFzMSRWZW50YXNfdG90YWxlcywgc3RhcnQgPSBjKDIwMTcsIDEpLCBlbmQ9YygyMDIyLDkpLCBmcmVxdWVuY3kgPSAxMikKCnByaW50KFZlbnRhcykKYGBgCgpMYSB2YXJpYWJsZSBkZXBlbmRpZW50ZSBzZSBkZWZpbmUgY29tbyAiVmVudGFzIFRvdGFsZXMiLCBjb3JyZXNwb25kaWVudGUgYSBsYXMgdmVudGFzIHRvdGFsZXMgcmVhbGl6YWRhcyBwb3IgRk9STS4KCmBgYHtyfQp0c19wbG90KFZlbnRhcykKYGBgCgpFbnRyZSAyMDE4IHkgMjAyMCwgbGEgc2VyaWUgZGUgdGllbXBvIG11ZXN0cmEgdW5hIHRlbmRlbmNpYSBsaW5lYWwuIFNpbiBlbWJhcmdvLCBkZXNwdcOpcyBkZSAyMDIwLCBlbWVyZ2UgdW4gcGF0csOzbiBlc3RhY2lvbmFsIGNsYXJvLCB5IGF1bnF1ZSBwdWVkZSBwcmVzZW50YXIgY2llcnRhIGVzdGFjaW9uYXJpZWRhZCwgc2Ugb2JzZXJ2YSB1bmEgdGVuZGVuY2lhIGFzY2VuZGVudGUgZ2VuZXJhbCBhIGxvIGxhcmdvIGRlIHRvZG8gZWwgcGVyaW9kbyBhbmFsaXphZG8uCgpgYGB7cn0KVmVudGFzZGVzYzwtZGVjb21wb3NlKFZlbnRhcykKcGxvdChWZW50YXNkZXNjKQpgYGAKCkxhIHRlbmRlbmNpYSwgcXVlIHJlcHJlc2VudGEgZWwgY29tcG9uZW50ZSBhIGxhcmdvIHBsYXpvIGRlIGxhIHNlcmllIGRlIHRpZW1wbywgaW5kaWNhIHVuIGF1bWVudG8gY29uc3RhbnRlIGVuIGxhcyB2ZW50YXMgdG90YWxlcyBkZSBGT1JNIGEgbG8gbGFyZ28gZGVsIHBlcmlvZG8gb2JzZXJ2YWRvLiAKCkxhIGVzdGFjaW9uYWxpZGFkLCBwb3Igb3RybyBsYWRvLCByZWZsZWphIGxhcyB2YXJpYWNpb25lcyBhIGNvcnRvIHBsYXpvLCByZXZlbGFuZG8gcXVlIGxhcyB2ZW50YXMgZGUgRk9STSB0aWVuZGVuIGEgaW5jcmVtZW50YXJzZSBlbiBkZXRlcm1pbmFkYXMgw6lwb2NhcyBkZWwgYcOxbywgY29tbyBlbCDDumx0aW1vIHRyaW1lc3RyZSwgeSBkaXNtaW51aXIgZW4gb3RyYXMsIGNvbW8gZWwgcHJpbWVyIHRyaW1lc3RyZSwgbG8gY3VhbCBwb2Ryw61hIGVzdGFyIHJlbGFjaW9uYWRvIGNvbiBlbCBhdW1lbnRvIHByb2dyZXNpdm8gZW4gbGEgZGVtYW5kYSBkZSBsb3MgY2xpZW50ZXMgYSBtZWRpZGEgcXVlIGF2YW56YSBlbCBhw7FvLCBzZWd1aWRvIGRlIHVuYSBjYcOtZGEgaGFjaWEgZWwgZmluYWwuIAoKTGEgYWxlYXRvcmllZGFkLCBlbCBjb21wb25lbnRlIGltcHJlZGVjaWJsZSBkZSBsYSBzZXJpZSBkZSB0aWVtcG8sIGluZGljYSBmbHVjdHVhY2lvbmVzIGVuIGxvcyBkYXRvcyBxdWUgbm8gc2UgZXhwbGljYW4gcG9yIGxhIHRlbmRlbmNpYSBuaSBwb3IgbGEgZXN0YWNpb25hbGlkYWQsIHN1Z2lyaWVuZG8gaW5jcmVtZW50b3MgaW5lc3BlcmFkb3MgZW4gbGEgZGVtYW5kYSBwb3IgcGFydGUgZGUgbG9zIGNsaWVudGVzLgoKYGBge3J9CmFkZi50ZXN0KHZlbnRhczEkVmVudGFzX3RvdGFsZXMpCmBgYAoKRGFkbyBxdWUgZWwgdmFsb3IgcCBkZSAwLjI4NCBzdXBlcmEgZWwgdW1icmFsIGRlIHNpZ25pZmljYW5jaWEgY29tw7pubWVudGUgYWNlcHRhZG8gZGUgMC4wNSwgbm8gY29udGFtb3MgY29uIHN1ZmljaWVudGUgZXZpZGVuY2lhIHBhcmEgZGVzY2FydGFyIGxhIGhpcMOzdGVzaXMgbnVsYSwgcXVlIGFzdW1lIGxhIG5vIGVzdGFjaW9uYXJpZWRhZCBkZSBsYSBzZXJpZSBkZSB0aWVtcG8uIFBvciBlbmRlLCBkZSBhY3VlcmRvIGNvbiBlc3RlIGFuw6FsaXNpcywgbGEgc2VyaWUgdGVtcG9yYWwgc2UgY29uc2lkZXJhIG5vIGVzdGFjaW9uYXJpYS4KCmBgYHtyfQphY2YodmVudGFzMSRWZW50YXNfdG90YWxlcykKYGBgCgpFbCBncsOhZmljbyBpbmRpY2EgcXVlIGxhIEZ1bmNpw7NuIGRlIEF1dG9jb3JyZWxhY2nDs24gKEFDRikgZXMgcG9zaXRpdmEgcGFyYSBsb3MgcmV6YWdvcyAxLCAyIHkgMywgbG8gcXVlIHN1Z2llcmUgdW5hIGNvcnJlbGFjacOzbiBwb3NpdGl2YSBlbnRyZSBsb3MgdmFsb3JlcyBkZSBsYSBzZXJpZSB0ZW1wb3JhbCBlbiBlc3RvcyBpbnRlcnZhbG9zLiBFc3RvIGltcGxpY2EgcXVlIGxvcyB2YWxvcmVzIGRlIGxhIHNlcmllIHRpZW5kZW4gYSBtb3ZlcnNlIGVuIGxhIG1pc21hIGRpcmVjY2nDs24gZW4gZXN0b3MgcGVyaW9kb3MuCgpQb3Igb3RybyBsYWRvLCBsYSBBQ0YgZXMgbmVnYXRpdmEgcGFyYSBsb3MgcmV6YWdvcyA0LCA1IHkgNiwgc2XDsWFsYW5kbyB1bmEgY29ycmVsYWNpw7NuIG5lZ2F0aXZhIGVuIGVzdG9zIHB1bnRvcy4gRXN0byBzaWduaWZpY2EgcXVlIGxvcyB2YWxvcmVzIGRlIGxhIHNlcmllIHRlbXBvcmFsIHRpZW5kZW4gYSBtb3ZlcnNlIGVuIGRpcmVjY2lvbmVzIG9wdWVzdGFzIGR1cmFudGUgZXN0b3MgaW50ZXJ2YWxvcy4KCkVzdGFzIGNhcmFjdGVyw61zdGljYXMgc3VnaWVyZW4gcXVlIGxhIHNlcmllIHRlbXBvcmFsIHBvZHLDrWEgZXhoaWJpciB1biBjb21wb3J0YW1pZW50byBlc3RhY2lvbmFsLCBkb25kZSBsYSBjb3JyZWxhY2nDs24gcG9zaXRpdmEgYSBjb3J0byBwbGF6byBpbmRpY2EgcGF0cm9uZXMgZGUgbW92aW1pZW50byBjb25qdW50byBkZWJpZG8gYSB0ZW5kZW5jaWFzIGVzdGFjaW9uYWxlcywgY29tbyBwZXLDrW9kb3MgZGUgYWx0YSBvIGJhamEgZGVtYW5kYSBkdXJhbnRlIGNpZXJ0YXMgw6lwb2NhcyBkZWwgYcOxby4gTGEgY29ycmVsYWNpw7NuIG5lZ2F0aXZhIGEgbcOhcyBsYXJnbyBwbGF6byBwb2Ryw61hIGluZGljYXIgdW5hIHRlbmRlbmNpYSBkZSBsb3MgdmFsb3JlcyBkZSBsYSBzZXJpZSBhIHJldG9ybmFyIGhhY2lhIHVuIHByb21lZGlvIGEgbG8gbGFyZ28gZGVsIHRpZW1wbywgcmVmbGVqYW5kbyB1bmEgcmV2ZXJzacOzbiBhIGxhIG1lZGlhIGVzdGFjaW9uYWwuCgojIyMjIE1vZGVsbyBBcm1hIENhbGN1bGFkbwoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kc3VtbWFyeShBUk1BPC1hcm1hKGRpZmYoVmVudGFzKSksb3JkZXI9YygxLDEpKQpgYGAKCmBgYHtyfQpwbG90KEFSTUEpCmBgYAoKRWwgdMOpcm1pbm8gQVIoMSkgZXMgc2lnbmlmaWNhdGl2byAocC12YWx1ZSA9IDAuMDE0NiksIGxvIHF1ZSBpbmRpY2EgcXVlIGVzIGltcG9ydGFudGUgZW4gZWwgbW9kZWxvLiBTaW4gZW1iYXJnbywgZWwgdMOpcm1pbm8gTUEoMSkgbm8gZXMgc2lnbmlmaWNhdGl2byAocC12YWx1ZSA9IDAuODE5OSkuCkxvcyByZXNpZHVvcyBkZWwgbW9kZWxvIHRpZW5lbiB1bmEgdmFyaWFuemEgZXN0aW1hZGEgKHNpZ21hXjIpIGRlIDEuODgyZSsxMiB5IGxvcyByZXN1bHRhZG9zIGRlbCBhanVzdGUgbXVlc3RyYW4gdW4gQUlDIGRlIDIxMjAuODguIEFkZW3DoXMsIHNlIGhhIGluY2x1aWRvIHVuIHTDqXJtaW5vIGRlIGludGVyY2VwdGFjacOzbiBjb24gdW4gdmFsb3IgZXN0aW1hZG8gZGUgMS4zODZlKzA1CgojIyMjIE1vZGVsbyBBcmltYSBDYWxjdWxhZG8KCmBgYHtyfQpzdW1tYXJ5KEFSSU1BPC1BcmltYShkaWZmKGxvZygoVmVudGFzKSkpLG9yZGVyPWMoMSwxLDEpKSkgCmBgYAoKYGBge3J9CnBsb3QoQVJJTUEpCmBgYAoKTG9zIGNvZWZpY2llbnRlcyBlc3RpbWFkb3MgcGFyYSBlbCB0w6lybWlubyBBUigxKSB5IGVsIHTDqXJtaW5vIE1BKDEpIHNvbiAtMC40OTc3IHkgLTEuMDAwMCByZXNwZWN0aXZhbWVudGUuIEVzdG8gaW5kaWNhIHF1ZSBoYXkgdW5hIHJlbGFjacOzbiBuZWdhdGl2YSBlbnRyZSBlbCB2YWxvciBhY3R1YWwgeSBsb3MgdmFsb3JlcyByZXphZ2Fkb3MuCgpMb3MgZXJyb3JlcyBlc3TDoW5kYXIgZGUgbG9zIGNvZWZpY2llbnRlcyAocy5lLikgc29uIDAuMTA0MCB5IDAuMDQyMiBwYXJhIGVsIHTDqXJtaW5vIEFSKDEpIHkgZWwgdMOpcm1pbm8gTUEoMSkgcmVzcGVjdGl2YW1lbnRlLgoKTGEgdmFyaWFuemEgZXN0aW1hZGEgZGUgbG9zIGVycm9yZXMgZGVsIG1vZGVsbyAoc2lnbWFeMikgZXMgZGUgYXByb3hpbWFkYW1lbnRlIDAuMDUxNjguCgpFbCBsb2dhcml0bW8gZGUgbGEgdmVyb3NpbWlsaXR1ZCBlcyBkZSBhcHJveGltYWRhbWVudGUgMi41NSB5IGVsIEFJQyBlcyBkZSAwLjkxLiBFc3RhcyBtZWRpZGFzIHByb3BvcmNpb25hbiBpbmZvcm1hY2nDs24gc29icmUgbGEgY2FsaWRhZCBkZWwgYWp1c3RlIGRlbCBtb2RlbG8sIGNvbiB2YWxvcmVzIG3DoXMgYmFqb3MgaW5kaWNhbmRvIHVuIG1lam9yIGFqdXN0ZS4KCkxhIHNlcmllIGRlIHRpZW1wbyBkZSBsYXMgdmVudGFzIG5vIGVzIGVzdGFjaW9uYXJpYSwgbG8gcXVlIHNpZ25pZmljYSBxdWUgbGEgbWVkaWEgeSBsYSB2YXJpYW56YSBkZSBsYSBzZXJpZSBkZSB0aWVtcG8gZXN0w6FuIGNhbWJpYW5kbyBjb24gZWwgdGllbXBvLgoKIyMjIyBFdmFsdWFjacOzbiBkZSBNb2RlbG9zCgoqKkFSTUEqKgpgYGB7cn0KYXJtYV9yZXNpZHVhbHM8LUFSTUEkcmVzaWR1YWxzCkJveC50ZXN0KGFybWFfcmVzaWR1YWxzLGxhZz0xLHR5cGU9IkxqdW5nLUJveCIpCmBgYAoKRXN0byBzaWduaWZpY2EgcXVlIG5vIHNlIGVuY29udHLDsyBldmlkZW5jaWEgc2lnbmlmaWNhdGl2YSBkZSBhdXRvY29ycmVsYWNpw7NuIGVuIGxvcyByZXNpZHVvcy4KCmBgYHtyfQpzdXBwcmVzc1dhcm5pbmdzKHsKQVJNQSRyZXNpZHVhbHMgPC0gbmEub21pdChBUk1BJHJlc2lkdWFscykKYWRmLnRlc3QoQVJNQSRyZXNpZHVhbHMpCn0pCmBgYAoKRGFkbyBxdWUgZWwgdmFsb3IgcCAoMC4wOTAzNCkgZXMgbWF5b3IgcXVlIGVsIG5pdmVsIGRlIHNpZ25pZmljYW5jaWEgY29tw7pubWVudGUgdXRpbGl6YWRvIGRlIDAuMDUsIG5vIHBvZGVtb3MgYWZpcm1hciBjb24gY29uZmlhbnphIHF1ZSBsb3MgcmVzaWR1b3Mgc2VhbiBlc3RhY2lvbmFyaW9zIHNlZ8O6biBlc3RhIHBydWViYS4gCgpgYGB7cn0KaGlzdChBUklNQSRyZXNpZHVhbHMpCmBgYAoKTGEgbm9ybWFsaWRhZCBzZSB2ZSBlbiBsb3MgcmVzaWR1YWxlcy4KCioqQVJJTUEqKgoKYGBge3J9CmFyaW1hX3Jlc2lkdWFsczwtQVJJTUEkcmVzaWR1YWxzCkJveC50ZXN0KGFyaW1hX3Jlc2lkdWFscyxsYWc9MSx0eXBlPSJManVuZy1Cb3giKQpgYGAKCkVzdG8gc2lnbmlmaWNhIHF1ZSBubyBzZSBlbmNvbnRyw7MgZXZpZGVuY2lhIHNpZ25pZmljYXRpdmEgZGUgYXV0b2NvcnJlbGFjacOzbiBlbiBsb3MgcmVzaWR1b3MuCgpgYGB7cn0Kc3VwcHJlc3NXYXJuaW5ncyh7CkFSSU1BJHJlc2lkdWFscyA8LSBuYS5vbWl0KEFSSU1BJHJlc2lkdWFscykKYWRmLnRlc3QoQVJJTUEkcmVzaWR1YWxzKQp9KQpgYGAKCkRhZG8gcXVlIGVsIHZhbG9yIHAgKDAuMDMxNTYpIGVzIG1lbm9yIHF1ZSBlbCBuaXZlbCBkZSBzaWduaWZpY2FuY2lhIGNvbcO6bm1lbnRlIHV0aWxpemFkbyBkZSAwLjA1LCBsb3MgcmVzaWR1b3MgcGFyZWNlbiBzZXIgZXN0YWNpb25hcmlvcyBzZWfDum4gZXN0YSBwcnVlYmEuIAoKYGBge3J9Cmhpc3QoQVJJTUEkcmVzaWR1YWxzKQpgYGAKCkxhIG5vcm1hbGlkYWQgc2UgdmUgZW4gbG9zIHJlc2lkdWFsZXMuCgojIyMjIFNlbGVjY2nDs24gZGUgTW9kZWxvCgpTZSBzZWxlY2Npb25vIGVsIG1vZGVsbyBBUklNQSwgeWEgcXVlIHRpZW5lIGVsIEFJQyBtYXMgYmFqbyBlbiBjb21wYXJhY2nDs24gY29uIGVsIG1vZGVsbyBBUk1BLgoKIyMjIyBGb3JlY2FzdCBkZSBWZW50YXMgZGUgRk9STQoKYGBge3J9CnN1cHByZXNzV2FybmluZ3MoewogICMgQXNpZ25hIGxhcyBwcmVkaWNjaW9uZXMgYWp1c3RhZGFzIHBvciBlbCBtb2RlbG8gQVJJTUEgYSBsYSB2YXJpYWJsZS4KICBhcmltYV9yZXN0YXVyYWNpb24gPC0gKEFSSU1BJGZpdHRlZCkKICAKICAjIENvbnZpZXJ0ZSBsYXMgcHJlZGljY2lvbmVzIGFqdXN0YWRhcyBlbiB1biB2ZWN0b3IuCiAgdmVjdG9yMiA8LSBjKGFyaW1hX3Jlc3RhdXJhY2lvbikKICAKICAjIENvbnZpZXJ0ZSBsb3MgZGF0b3Mgb3JpZ2luYWxlcyBkZSB2ZW50YXMgZW4gdW4gdmVjdG9yLgogIG9yaWdpbmFsMiA8LSBjKFZlbnRhcykKICAKICAjIFJlYWxpemEgbGEgb3BlcmFjacOzbiBpbnZlcnNhIGEgbGEgZGlmZXJlbmNpYSwgc3VtYW5kbyBsb3MgdmFsb3JlcyBvcmlnaW5hbGVzIGEgbGFzIGRpZmVyZW5jaWFzLgogIHJlc3RhdXJhY2lvbjIgPC0gdmVjdG9yMiArIG9yaWdpbmFsMgogIAogICMgQ29udmllcnRlIGVsIHZlY3RvciByZXN0YXVyYWRvIGVuIHVuYSBzZXJpZSB0ZW1wb3JhbCwgZXNwZWNpZmljYW5kbyBpbmljaW8sIGZpbiB5IGZyZWN1ZW5jaWEuCiAgdHMyIDwtIHRzKHJlc3RhdXJhY2lvbjIsIHN0YXJ0ID0gMSwgZW5kID0gbGVuZ3RoKHJlc3RhdXJhY2lvbjIpLCBmcmVxdWVuY3kgPSAxMikKfSkKYGBgCgoKYGBge3J9CmFyaW1hX2ZvcmVjYXN0PC1mb3JlY2FzdCh0czIsaD01KQphcmltYV9mb3JlY2FzdApgYGAKCmBgYHtyfQpwbG90KGFyaW1hX2ZvcmVjYXN0KQpgYGAKCmBgYHtyfQphdXRvcGxvdChhcmltYV9mb3JlY2FzdCkKYGBgCgoqKkZvcmVjYXN0IENhbGN1bGFkbyoqCgpMb3MgcHJvbsOzc3RpY29zIHBhcmEgbG9zIHByw7N4aW1vcyBwZXJpb2RvcyBzZSBwcmVzZW50YW4gYSBjb250aW51YWNpw7NuLCByZWZsZWphbmRvIGxhcyBleHBlY3RhdGl2YXMgZGUgdmVudGFzIGZ1dHVyYXMgYmFzYWRhcyBlbiBlbCBhbsOhbGlzaXMgcmVhbGl6YWRvOgoKLSAqKlBlcmlvZG8gMToqKiA1LDg0Miw3NDIKLSAqKlBlcmlvZG8gMjoqKiA2LDQzOSwzMjMKLSAqKlBlcmlvZG8gMzoqKiA1LDgwNyw4MDAKLSAqKlBlcmlvZG8gNDoqKiA1LDk4NiwzODgKLSAqKlBlcmlvZG8gNToqKiA2LDU1Myw2MjkKCkNhZGEgdmFsb3IgcmVwcmVzZW50YSBsYSBwcm95ZWNjacOzbiBkZSB2ZW50YXMgcGFyYSBlbCBwZXJpb2RvIGNvcnJlc3BvbmRpZW50ZSwgaW5kaWNhbmRvIGZsdWN0dWFjaW9uZXMgZW4gbGEgZGVtYW5kYSBvIGVuIGxhcyB0ZW5kZW5jaWFzIGRlIHZlbnRhcyBpZGVudGlmaWNhZGFzIHBvciBlbCBtb2RlbG8uIEVzdG9zIHByb27Ds3N0aWNvcyBzb24gY3J1Y2lhbGVzIHBhcmEgbGEgcGxhbmlmaWNhY2nDs24gZXN0cmF0w6lnaWNhIHkgbGEgdG9tYSBkZSBkZWNpc2lvbmVzIGVuIGVsIMOhbWJpdG8gZW1wcmVzYXJpYWwuCgojIyMjIE1vZGVsbyBWYXIgQ2FsY3VsYWRvCgpEZWwgY29uanVudG8gZGUgZGF0b3MsIHNlIHNlbGVjY2lvbmFyb24gbGFzIHZhcmlhYmxlcyBleHBsaWNhdGl2YXMgcXVlIHBvZHLDrWFuIGV4cGxpY2FyIGxhcyB2ZW50YXMgZGUgRk9STS4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnNldHdkKCIuLi9kYXRhYmFzZXMvIikKdmVudGFzMiA8LSByZWFkX2V4Y2VsKCJmb3JtL0ZPUk0tVmVudGFzLnhsc3giKQoKbmFtZXModmVudGFzMilbbmFtZXModmVudGFzMikgPT0gIlZlbnRhcyBUb3RhbGVzIl0gPC0gIlZlbnRhc190b3RhbGVzIgpuYW1lcyh2ZW50YXMyKVtuYW1lcyh2ZW50YXMyKSA9PSAiVG90YWwgQ2FydG9uIl0gPC0gIlRvdGFsX2NhcnRvbiIKbmFtZXModmVudGFzMilbbmFtZXModmVudGFzMikgPT0gIlRvdGFsIFJldG9ybmFibGUiXSA8LSAiVG90YWxfcmV0b3JuYWJsZSIKbmFtZXModmVudGFzMilbbmFtZXModmVudGFzMikgPT0gIlZhcmlhY2nDs24iXSA8LSAiVmFyaWFjaW9uIgpgYGAKCiMjIyMgSW1wYWN0byBkZSBWYXJpYWJsZXMgc29icmUgVmVudGFzCgpgYGB7cn0KU3lzLnNldGxvY2FsZSgiTENfVElNRSIsICJlc19FUy5VVEYtOCIpCnZlbnRhczIgPC0gbmEub21pdCh2ZW50YXMyWywgYygiQcOxbyIsICJNZXMiLCAiVmVudGFzX3RvdGFsZXMiLCAiVG90YWxfY2FydG9uIiwgIlRvdGFsX3JldG9ybmFibGUiLCAiVmFyaWFjaW9uIiwgIlNlcnZpY2lvcyIsICJNdWVzdHJhcyIpXSkKdmVudGFzMiRGZWNoYSA8LSBhcy5EYXRlKHBhc3RlKHZlbnRhczIkQcOxbywgdmVudGFzMiRNZXMsICIwMSIpLCBmb3JtYXQgPSAiJVkgJUIgJWQiKQpWZW50YXMyIDwtIHRzKHZlbnRhczIkVmVudGFzX3RvdGFsZXMsIHN0YXJ0ID0gYyhhcy5udW1lcmljKGZvcm1hdChtaW4odmVudGFzMiRGZWNoYSksICIlWSIpKSwgYXMubnVtZXJpYyhmb3JtYXQobWluKHZlbnRhczIkRmVjaGEpLCAiJW0iKSkpLCBmcmVxdWVuY3kgPSAxMikKcGxvdChWZW50YXMyKQpgYGAKCmBgYHtyfQpDYXJ0b24gPC0gdHModmVudGFzMiRUb3RhbF9jYXJ0b24sIHN0YXJ0ID0gYyh5ZWFyKG1pbih2ZW50YXMyJEZlY2hhKSksIG1vbnRoKG1pbih2ZW50YXMyJEZlY2hhKSkpLCBmcmVxdWVuY3kgPSAxMikKCnRzX3Bsb3QoQ2FydG9uKQpgYGAKCgpgYGB7cn0KUmV0b3JuYWJsZSA8LSB0cyh2ZW50YXMyJFRvdGFsX3JldG9ybmFibGUsIHN0YXJ0ID0gYyh5ZWFyKG1pbih2ZW50YXMyJEZlY2hhKSksIG1vbnRoKG1pbih2ZW50YXMyJEZlY2hhKSkpLCBmcmVxdWVuY3kgPSAxMikKdHNfcGxvdChSZXRvcm5hYmxlKQpgYGAKCgpgYGB7cn0Kc2VydmljaW8gPC0gdHModmVudGFzMiRTZXJ2aWNpb3MsIHN0YXJ0ID0gYyh5ZWFyKG1pbih2ZW50YXMyJEZlY2hhKSksIG1vbnRoKG1pbih2ZW50YXMyJEZlY2hhKSkpLCBmcmVxdWVuY3kgPSAxMikKdHNfcGxvdChzZXJ2aWNpbykKYGBgCgoKYGBge3J9Cm11ZXN0cmEgPC0gdHModmVudGFzMiRNdWVzdHJhcywgc3RhcnQgPSBjKHllYXIobWluKHZlbnRhczIkRmVjaGEpKSwgbW9udGgobWluKHZlbnRhczIkRmVjaGEpKSksIGZyZXF1ZW5jeSA9IDEyKQp0c19wbG90KG11ZXN0cmEpCmBgYAoKCmBgYHtyfQp2YXJpYWNpb24gPC0gdHModmVudGFzMiRWYXJpYWNpb24sIHN0YXJ0ID0gYyh5ZWFyKG1pbih2ZW50YXMyJEZlY2hhKSksIG1vbnRoKG1pbih2ZW50YXMyJEZlY2hhKSkpLCBmcmVxdWVuY3kgPSAxMikKdHNfcGxvdCh2YXJpYWNpb24pCmBgYAoKVG90YWwgY2FydMOzbjogYWwgaWd1YWwgcXVlIGxhIHZhcmlhYmxlIGRlcGVuZGllbnRlLCBtdWVzdHJhIHVuYSB0ZW5kZW5jaWEgZGUgY3JlY2ltaWVudG8sIGVzdG8gcHVlZGUgc2lnbmlmaWNhciBxdWUgZXN0YW4gYWx0YW1lbnRlIHJlbGFjaW9uYWRhcy4KClRvdGFsIHJldG9ybmFibGU6IGFsIGlndWFsIHF1ZSBsYSB2YXJpYWJsZSBkZXBlbmRpZW50ZSwgbXVlc3RyYSB1bmEgdGVuZGVuY2lhIGRlIGNyZWNpbWllbnRvLCBlc3RvIHB1ZWRlIHNpZ25pZmljYXIgcXVlIGVzdGFuIGFsdGFtZW50ZSByZWxhY2lvbmFkYXMuCgpTZXJpdmljb3M6IExhIHNlcmllIHRlbXBvcmFsIG5vIG11ZXN0cmEgdW5hIHJlbGFjacOzbiBjbGFyYSBlbnRyZSBsb3Mgc2VydmljaW9zIHkgbGFzIHZlbnRhcywgZXN0byBwdWVkZSBzZXIgZGViaWRvIGEgbGEgZGVtYW5kYSBkZWwgbWVyY2Fkby4gCgojIyMjIFRlc3RzIGRlIERpYWdub3N0aWNvCgpgYGB7cn0KYWRmLnRlc3QoQ2FydG9uKSAKYGBgCgpEYWRvIHF1ZSBlbCB2YWxvciBwICgwLjk1OTQpIGVzIG11Y2hvIG1heW9yIHF1ZSBlbCBuaXZlbCBkZSBzaWduaWZpY2FuY2lhIGNvbcO6bm1lbnRlIHV0aWxpemFkbyBkZSAwLjA1LCBvIHBvZGVtb3MgYWZpcm1hciBjb24gY29uZmlhbnphIHF1ZSBsYSBzZXJpZSAiQ2FydG9uIiBzZWEgZXN0YWNpb25hcmlhIHNlZ8O6biBlc3RhIHBydWViYS4KCmBgYHtyfQphZGYudGVzdChSZXRvcm5hYmxlKSAKYGBgCgpEYWRvIHF1ZSBlbCB2YWxvciBwICgwLjgyNzIpIGVzIG11Y2hvIG1heW9yIHF1ZSBlbCBuaXZlbCBkZSBzaWduaWZpY2FuY2lhIGNvbcO6bm1lbnRlIHV0aWxpemFkbyBkZSAwLjA1LCBvIHBvZGVtb3MgYWZpcm1hciBjb24gY29uZmlhbnphIHF1ZSBsYSBzZXJpZSAiQ2FydG9uIiBzZWEgZXN0YWNpb25hcmlhIHNlZ8O6biBlc3RhIHBydWViYS4KCiMjIyMgRXZhbHVhY2nDs24gZGUgTW9kZWxvcyBWYXIKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnZhcl90czwtY2JpbmQoZGlmZihsb2coVmVudGFzMikpLCBkaWZmKGxvZyhDYXJ0b24pKSwgZGlmZihsb2coUmV0b3JuYWJsZSkpKQpjb2xuYW1lcyh2YXJfdHMpPC1jYmluZCgiVmVudGFzXzIiLCAiQ2FydG9uIiwgIlJldG9ybmFibGUiKSAKYWNmX3Zhcl90cyA8LSBsYXBwbHkodmFyX3RzLCBhY2YpCmhlYWQodmFyX3RzKQpgYGAKCmBgYHtyfQp2YXJfdHMgPC0gdHModmFyX3RzLCBmcmVxdWVuY3kgPSAxLCBzdGFydCA9IGMoMjAyMikpCgojIFJlYWxpemEgbGEgc2VsZWNjacOzbiBkZSByZXphZ29zCmxhZ19zZWxlY3Rpb24gPC0gVkFSc2VsZWN0KHZhcl90cyxsYWcubWF4PTMsdHlwZT0iY29uc3QiLCBzZWFzb249MTIpCgojIEltcHJpbWUgbG9zIHJlc3VsdGFkb3MKbGFnX3NlbGVjdGlvbiRzZWxlY3Rpb24KYGBgCgpgYGB7cn0KbGFnX3NlbGVjdGlvbiRjcml0ZXJpYQp2YXJfdHMKYGBgCgojIyMjIFJlc3RyaWNjaW9uZXMgZGUgTW9kZWxvIFZhcgoKYGBge3J9CnZhcl9tb2RlbG88LVZBUih2YXJfdHMscD0xKSAKI3N1bW1hcnkoVkFSX2V2Mm1vZGVsMSkKbWF0cml6X2NvcnJlbGFjaW9uIDwtIGNvcih2YXJfdHMpCiMgSW1wcmltaXIgbGEgbWF0cml6IGRlIGNvcnJlbGFjacOzbgpwcmludChtYXRyaXpfY29ycmVsYWNpb24pCmBgYAoKTm8gZXMgcG9zaWJsZSBhcGxpY2FyIGVsIG1vZGVsbyBWQVIgZGViaWRvIGEgbGEgYWx0YSBjb3JyZWxhY2nDs24gZW50cmUgbGFzIHZhcmlhYmxlcyBleHBsaWNhdGl2YXMgeSBsYSB2YXJpYWJsZSBkZXBlbmRpZW50ZS4gRXN0ZSBmZW7Ds21lbm8gcG9kcsOtYSBleHBsaWNhcnNlIHBvciBlbCBoZWNobyBkZSBxdWUgZWwgKip0b3RhbCBkZSBjYXJ0w7NuKiogeSBlbCAqKnRvdGFsIGRlIHJldG9ybmFibGUqKiBjb25zdGl0dXllbiBjb25qdW50YW1lbnRlIGVsICoqdG90YWwgZGUgdmVudGFzKiouIExhIG1hdHJpeiBkZSBjb3JyZWxhY2nDs24gcmV2ZWxhIGxvIHNpZ3VpZW50ZToKCi0gTGEgY29ycmVsYWNpw7NuIGVudHJlIGBWZW50YXNfMmAgeSBgQ2FydG9uYCBlcyBhcHJveGltYWRhbWVudGUgKiowLjUwMzcqKi4gRXN0byBzdWdpZXJlIHVuYSBjb3JyZWxhY2nDs24gcG9zaXRpdmEgbW9kZXJhZGEgZW50cmUgZXN0YXMgZG9zIHZhcmlhYmxlcy4KLSBMYSBjb3JyZWxhY2nDs24gZW50cmUgYFZlbnRhc18yYCB5IGBSZXRvcm5hYmxlYCBlcyBhcHJveGltYWRhbWVudGUgKiowLjMzMzYqKi4gRXN0byB0YW1iacOpbiBpbmRpY2EgdW5hIGNvcnJlbGFjacOzbiBwb3NpdGl2YSwgcGVybyBtw6FzIGTDqWJpbCBlbiBjb21wYXJhY2nDs24gY29uIGxhIGNvcnJlbGFjacOzbiBlbnRyZSBgVmVudGFzXzJgIHkgYENhcnRvbmAuCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQptb2RlbG8gPC0gbG0oVmVudGFzX3RvdGFsZXMgfiBUb3RhbF9jYXJ0b24gKyBUb3RhbF9yZXRvcm5hYmxlICsgc2VydmljaW8gKyBtdWVzdHJhICsgdmFyaWFjaW9uLCBkYXRhID0gdmVudGFzMikKZHVyYmluV2F0c29uVGVzdChtb2RlbG8pCmBgYAoKU2Vnw7puIGVsIHRlc3QgZGUgRHVyYmluLVdhdHNvbiwgbm8gaGF5IGV2aWRlbmNpYSBkZSBhdXRvY29ycmVsYWNpw7NuIGRlIHByaW1lciBvcmRlbiBlbiBsb3MgcmVzaWR1b3MgZGVsIG1vZGVsbyBkZSByZWdyZXNpw7NuIGxpbmVhbC4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnZhcl9yZXNpZHVhbHM8LWRhdGEuZnJhbWUocmVzaWR1YWxzKHZhcl9tb2RlbG8pKQoKZm9yZWNhc3RfMjwtcHJlZGljdCh2YXJfbW9kZWxvLG4uYWhlYWQ9NSxjaT0wLjk1KSAjIyMgZm9yZWNhc3QgZm9yIHRoZSBuZXh0IDEyIG1vbnRocwpmYW5jaGFydChmb3JlY2FzdF8yLG5hbWVzPSJWZW50YXMiLG1haW49IlZlbnRhcyIseGxhYj0iVGltZSBQZXJpb2QiLHlsYWI9IlZlbnRhcyIpCmBgYAoKYGBge3J9CmZvcmVjYXN0XzIKYGBgCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpmb3JlY2FzdF8yJGZjc3QkVmVudGFzXzIgPC0gZXhwKGZvcmVjYXN0XzIkZmNzdCRWZW50YXNfMikgIAoKCmZvcmVjYXN0XzIkZmNzdCRWZW50YXNfMlsxXSA9IGZvcmVjYXN0XzIkZmNzdCRWZW50YXNfMlsxXSArIHRhaWwodmVudGFzMiRWZW50YXNfdG90YWxlcywgMSkKZm9yZWNhc3RfMiRmY3N0JFZlbnRhc18yWzJdID0gZm9yZWNhc3RfMiRmY3N0JFZlbnRhc18yWzJdICsgdGFpbCh2ZW50YXMyJFZlbnRhc190b3RhbGVzLCAxKQpmb3JlY2FzdF8yJGZjc3QkVmVudGFzXzJbM10gPSBmb3JlY2FzdF8yJGZjc3QkVmVudGFzXzJbM10gKyB0YWlsKHZlbnRhczIkVmVudGFzX3RvdGFsZXMsIDIpCmZvcmVjYXN0XzIkZmNzdCRWZW50YXNfMls0XSA9IGZvcmVjYXN0XzIkZmNzdCRWZW50YXNfMls0XSArIHRhaWwodmVudGFzMiRWZW50YXNfdG90YWxlcywgMykKZm9yZWNhc3RfMiRmY3N0JFZlbnRhc18yWzVdID0gZm9yZWNhc3RfMiRmY3N0JFZlbnRhc18yWzVdICsgdGFpbCh2ZW50YXMyJFZlbnRhc190b3RhbGVzLCA0KQpgYGAKCmBgYHtyfQpmb3JlY2FzdF8yJGZjc3QkVmVudGFzXzIKYGBgCgojIyMjIEZvcmVjYXN0IGRlIFZlbnRhcyBwYXJhIE1vZGVsbyBWQVIKClByZXNlbnRhbW9zIGEgY29udGludWFjacOzbiBsYXMgcHJveWVjY2lvbmVzIGRlIHZlbnRhcyB1dGlsaXphbmRvIGVsIG1vZGVsbyBWQVIgcGFyYSBsb3MgcHLDs3hpbW9zIGNpbmNvIHBlcmlvZG9zLiBFc3RhcyBlc3RpbWFjaW9uZXMgbm9zIHBlcm1pdGVuIGFudGljaXBhciBsYSBkaW7DoW1pY2EgZGVsIG1lcmNhZG8geSBhanVzdGFyIG51ZXN0cmFzIGVzdHJhdGVnaWFzIG9wZXJhdGl2YXMgeSBmaW5hbmNpZXJhcyBhY29yZGUgYSBsYXMgZXhwZWN0YXRpdmFzIGZ1dHVyYXM6CgotICoqUGVyaW9kbyAxOioqIFNlIGVzcGVyYSBxdWUgbGFzIHZlbnRhcyBhbGNhbmNlbiBsb3MgMTEsNTc3LDUyOSwgbWFudGVuaWVuZG8gdW5hIGzDrW5lYSBjb24gbG9zIHJlc3VsdGFkb3MgYW50ZXJpb3Jlcy4KLSAqKlBlcmlvZG8gMjoqKiBMYXMgdmVudGFzIHNlIHByb3llY3RhbiBlc3RhYmxlcywgc2luIHZhcmlhY2nDs24gcmVzcGVjdG8gYWwgcGVyaW9kbyBhbnRlcmlvciwgZW4gMTEsNTc3LDUyOS4KLSAqKlBlcmlvZG8gMzoqKiBTZSBhbnRpY2lwYSB1bmEgbGV2ZSBkaXNtaW51Y2nDs24gZW4gbGFzIHZlbnRhcywgc2l0dcOhbmRvc2UgZW4gMTEsMDUzLDAxOCwgbG8gcXVlIHBvZHLDrWEgcmVmbGVqYXIgYWp1c3RlcyBlc3RhY2lvbmFsZXMgbyBkZSBtZXJjYWRvLgotICoqUGVyaW9kbyA0OioqIFNlIHByZXbDqSB1bmEgcmVkdWNjacOzbiBtw6FzIG5vdGFibGUgZW4gbGFzIHZlbnRhcywgZGVzY2VuZGllbmRvIGEgOSw0OTUsMjA4LiBFc3RlIHBlcmlvZG8gcmVxdWVyaXLDoSBhdGVuY2nDs24gcGFyYSBtaXRpZ2FyIGxvcyBpbXBhY3RvcyBuZWdhdGl2b3MuCi0gKipQZXJpb2RvIDU6KiogTGFzIHZlbnRhcyBwb2Ryw61hbiBkaXNtaW51aXIgaGFzdGEgbG9zIDgsNjIzLDQ0NSwgaW5kaWNhbmRvIGxhIGltcG9ydGFuY2lhIGRlIGRlc2Fycm9sbGFyIGVzdHJhdGVnaWFzIGRlIHJlY3VwZXJhY2nDs24geSBhZGFwdGFjacOzbi4KCkVzdGFzIHByb3llY2Npb25lcyBzb24gdW5hIGhlcnJhbWllbnRhIHZpdGFsIHBhcmEgbGEgcGxhbmlmaWNhY2nDs24gZXN0cmF0w6lnaWNhLCBwZXJtaXRpw6luZG9ub3MgcHJlcGFyYXIgY29uIGFudGljaXBhY2nDs24gcGFyYSBsb3MgY2FtYmlvcyBlbiBlbCBlbnRvcm5vIGRlIHZlbnRhcy4KCiMjIyMgSW5zaWdodHMgZGUgQW1ib3MgTW9kZWxvcwoKTG9zIHByb27Ds3N0aWNvcyBwYXJhIGxhcyB2ZW50YXMgZW4gbG9zIHByw7N4aW1vcyBjaW5jbyBwZXLDrW9kb3MgcmV2ZWxhbiB0ZW5kZW5jaWFzIHkgZGVzYWbDrW9zIGltcG9ydGFudGVzIHBhcmEgZWwgZnV0dXJvIHByw7N4aW1vLiBBbCBpbmljaW8sIHNlIGVzcGVyYSBxdWUgbGFzIHZlbnRhcyBzZSBtYW50ZW5nYW4gZXN0YWJsZXMsIGFsY2FuemFuZG8gdW5hIGNpZnJhIHByb3llY3RhZGEgZGUgYWxyZWRlZG9yIGRlIDExLDU3Nyw1MjkgZW4gZWwgcHJpbWVyIHBlcsOtb2RvLiBFc3RhIGVzdGFiaWxpZGFkIHN1Z2llcmUgdW5hIGZhc2UgZGUgbWVyY2FkbyBzaW4gZ3JhbmRlcyBjYW1iaW9zLCBvZnJlY2llbmRvIHVuYSBvcG9ydHVuaWRhZCBwYXJhIGNvbnNvbGlkYXIgZXN0cmF0ZWdpYXMgYWN0dWFsZXMuCgpQYXJhIGVsIHNlZ3VuZG8gcGVyw61vZG8sIGxhcyBwcm95ZWNjaW9uZXMgaW5kaWNhbiB1bmEgY29udGludWlkYWQgZW4gZXN0YSB0ZW5kZW5jaWEsIGNvbiB2ZW50YXMgZXNwZXJhZGFzIHNpbWlsYXJlcyBhIGxhcyBkZWwgcHJpbWVyIHBlcsOtb2RvLiBFc3RhIHBlcnNpc3RlbmNpYSBzdWJyYXlhIHVuYSBldGFwYSBkZSBlc3RhYmlsaWRhZCwgcG9zaWJsZW1lbnRlIGRlYmlkbyBhIGxhIGVmZWN0aXZpZGFkIGRlIGxhcyBlc3RyYXRlZ2lhcyBkZSBtZXJjYWRvIGFjdHVhbGVzIG8gYSB1biBlcXVpbGlicmlvIGVuIGxhIGRpbsOhbWljYSBkZSBkZW1hbmRhIHkgb2ZlcnRhLgoKTm8gb2JzdGFudGUsIGVsIGVzY2VuYXJpbyBzZSBtb2RpZmljYSBsaWdlcmFtZW50ZSBlbiBlbCB0ZXJjZXIgcGVyw61vZG8sIGRvbmRlIHNlIHByZXbDqSB1biBkZXNjZW5zbyBlbiBsYXMgdmVudGFzIGhhc3RhIDExLDA1MywwMTguIEVzdGUgbGlnZXJvIHJldHJvY2VzbyBwb2Ryw61hIHNlciB1biBpbmRpY2F0aXZvIGRlIHVuYSBkaXNtaW51Y2nDs24gZW4gbGEgZGVtYW5kYSBvIGRlIGxhIGluZmx1ZW5jaWEgZGUgZmFjdG9yZXMgZXh0ZXJub3MgcXVlIGFmZWN0YW4gbmVnYXRpdmFtZW50ZSBlbCB2b2x1bWVuIGRlIHZlbnRhcy4KCkVsIGN1YXJ0byBwZXLDrW9kbyBwcmVzZW50YSByZXRvcyBtw6FzIHNpZ25pZmljYXRpdm9zLCBjb24gdW5hIHByb3llY2Npw7NuIGRlIHZlbnRhcyBxdWUgZGlzbWludXllIGNvbnNpZGVyYWJsZW1lbnRlIGEgOSw0OTUsMjA4LiBFc3RlIG5vdGFibGUgZGVjbGl2ZSBzZcOxYWxhIGxhIG5lY2VzaWRhZCBkZSByZXZpc2FyIGNyw610aWNhbWVudGUgbGFzIGVzdHJhdGVnaWFzIGRlIG1lcmNhZG8geSwgcG9zaWJsZW1lbnRlLCBhZGFwdGFyc2UgYSB1biBlbnRvcm5vIGNvbXBldGl0aXZvIG3DoXMgYWdyZXNpdm8gbyBhIGNhbWJpb3MgZW4gbGFzIHByZWZlcmVuY2lhcyBkZSBsb3MgY29uc3VtaWRvcmVzLgoKRmluYWxtZW50ZSwgZWwgcXVpbnRvIHBlcsOtb2RvIGNvbnRpbsO6YSBjb24gZXN0YSB0ZW5kZW5jaWEgZGUgZGVjcmVjaW1pZW50bywgZXZpZGVuY2lhbmRvIHVuYSByZWR1Y2Npw7NuIGFkaWNpb25hbCBlbiBsYXMgdmVudGFzLiBFc3RlIHBhdHLDs24gc3VnaWVyZSB1biBhdW1lbnRvIGVuIGxhIGNvbXBldGVuY2lhIG8gdW5hIHNpZ25pZmljYXRpdmEgZGlzbWludWNpw7NuIGVuIGxhIGRlbWFuZGEsIGRlc3RhY2FuZG8gbGEgaW1wb3J0YW5jaWEgZGUgdW5hIGVzdHJhdGVnaWEgZW1wcmVzYXJpYWwgZmxleGlibGUgeSBwcm9hY3RpdmEgcGFyYSBzdXBlcmFyIGVzdG9zIGRlc2Fmw61vcyB5IGZvbWVudGFyIHVuIGNyZWNpbWllbnRvIHJlbm92YWRvLgoKRXN0b3MgcHJvbsOzc3RpY29zIG5vIHNvbG8gcHJvcG9yY2lvbmFuIHVuYSB2aXNpw7NuIGRlIGxvcyBwb3NpYmxlcyBlc2NlbmFyaW9zIGZ1dHVyb3MsIHNpbm8gcXVlIHRhbWJpw6luIGVuZmF0aXphbiBsYSBuZWNlc2lkYWQgZGUgYWRhcHRhYmlsaWRhZCB5IHByb2FjdGl2aWRhZCBlbiBsYSBwbGFuaWZpY2FjacOzbiBlc3RyYXTDqWdpY2EgcGFyYSBtYW50ZW5lciBsYSByZWxldmFuY2lhIHkgY29tcGV0aXRpdmlkYWQgZW4gdW4gbWVyY2FkbyBkaW7DoW1pY28uCgojIyBEaXNlw7FvLCBPcmdhbml6YWNpw7NuLCB5IExpbXBpZXphIGRlIEJhc2UgZGUgRGF0b3MKCiMjIyBTZWxlY2Npw7NuIGRlIEluZm9ybWFjacOzbgpTZWxlY2Npb25hciBpbmZvcm1hY2nDs24geSBkYXRvcyBxdWUgY29uc2lkZXJlbiByZWxldmFudGVzIHBhcmEgcmVzcG9uZGVyIGxhcyBwcmVndW50YXMgZGUgYW7DoWxpc2lzLgoKKiogQmFzZSBkZSBEYXRvcyBNYWVzdHJhIHBhcmEgU2l0dWFjacOzbiBQcm9ibGVtYSAxKioKCkRhZG8gcXVlIGxhIHByaW1lcmEgc2l0dWFjacOzbiBwcm9ibGVtYSB0aWVuZSB1biBlbmZvcXVlIGNvbiBiYXNlIGludGVybmEsIGVzIG5lY2VzYXJpbyB1dGlsaXphciBsYXMgYmFzZXMgZGUgZGF0b3MgcmVsYWNpb25hZGFzIGFsIGFyZWEgZGUgY2FwaXRhbCBodW1hbm8gcGFyYSByZXNvbHZlciBlc3RlIHByb2JsZW1hLiBEYWRvIHF1ZSBoYXN0YSBsYSBmZWNoYSBhY3R1YWwgbGEgZW1wcmVzYSBGT1JNIHVuaWNhbWVudGUgaGEgcHJvcG9yY2lvbmFkbyAyIGJhc2VzIGRlIGRhdG9zIHJlbGFjaW9uYWRhcyBhIGRpY2hhIHByb2JsZW1hdGljYSwgYWN0dWFsbWVudGUgc29sbyBzZSBsaW1waWFyb24geSB1bmlmaWNhcm9uIGVzYXMgYmFzZXMgZGl2aWRpZW5kb3NlIGVuIDIgYmFzZXMgbWFlc3RyYXMgYWN0dWFsbWVudGUsIEZPUk1fQmFqYXMgeSBGT1JNX1NhdGlzZmFjY2lvbiwgY2FkYSB1bmEgdGVuaWVuZG8gdW4gZW5mb3F1ZSBkaXN0aW50by4gQWRlbcOhcyBkZSBlc3RvLCBzZSBkZXNjYXJnbyBsYSBiYXNlIGRlIGRhdG9zIG9mZmljaWFsIHByb3BvcmNpb25hZGEgcG9yIHBhcnRlIGRlbCBHb3ZpZXJubyBkZSBNZXhpY28geSBkZSBsaWJyZSB1c28gcXVlIGluY2x1eWUgbG9zIHBvbGlnb25vcyBwYXJhIGxsZXZhciBhIGNhYm8gdW4gYW5hbGlzaXMgZXNwYWNpYWwuIERlIGVzdGEgZm9ybWEgZSBpbnRlZ3JhbmRvIGVzdGEgdWx0aW1hIGJhc2UgZGUgZGF0b3MsIHBvZHLDrWFtb3MgdGVuZXIgYW1iYXMgYmFzZXMgbGlzdGFzIHBhcmEgbGEgY3JlYWNpw7NuIGRlIHVuIG1vZGVsbyBkZSBjbGFzaWZpY2FjacOzbi4KCioqIEJhc2UgZGUgRGF0b3MgTWFlc3RyYSBwYXJhIFNpdHVhY2nDs24gUHJvYmxlbWEgMioqCgpDb24gcmVzcGVjdG8gYSBsYXMgcHJvYmxlbWF0aWNhcyBhc29jaWFkYXMgYSBsYSBzaXR1YWNpw7NuIHByb2JsZW1hIDIsIGFjdHVhbG1lbnRlIG5vIHNlIGN1ZW50YSBjb24gbGEgZGF0YSBpbnRlcm5hIHN1ZmljaWVudGUgY29tbyBwYXJhIHBvZGVyIGNyZWFyIHVuYSBiYXNlIG1hZXN0cmEgbGlzdGEgcXVlIG5vcyBwZXJtaXRhIGNyZWFyIHVuIG1vZGVsbyB1dGlsIHkgcmVhbCBxdWUgcGVybWl0YSBhbCBzb2NpbyBmb3JtYWRvciBwcmVkZWNpciBsYSBkZW1hbmRhLiBBIHBlc2FyIGRlIGVzdG8sIGNvbnRhbW9zIGFjdHVhbG1lbnRlIGNvbiB1bmEgYmFzZSBkZSBkYXRvcyBsaWdhZGEgYWwgZmVub21lbm8gZGUgbmVhcnNob3JpbmcsIHVuYSBiYXNlIGRlIGRhdG9zIHVuaWZpY2FkYSBwYXJhIGxhIGV4cG9ydGFjacOzbiBlIGltcG9ydGFjacOzbiBkZSBtYXRlcmlhIHByaW1hIHkgZGUgbGFzIGluZHVzdHJpYXMgbWFudWZhY3R1cmVyYXMgcmVsYWNpb25hZGFzIHF1ZSBzaSBiaWVuIG5vIHNlIGhhbiB1bmlmaWNhZG9zIHRvZGFzIGxhcyBiYXNlcyBlbiAxLCB5YSBoYXkgdW5hIGJhc2UgbWFlc3RyYSBwYXJhIGNhZGEgY2FtcG8gcXVlIHNlIHB1ZWRlIGVuY29udHJhciBkZW50cm8gZGUgbGEgY2FycGV0YSBkZSBkYXRhYmFzZXMgZW4gZXN0ZSBtaXNtbyByZXBvc2l0b3Jpby4gVW5hIHZleiBjb24gZGF0b3MgbcOhcyBlc3BlY2lmaWNvcyBkZSBwcm9kdWNjacOzbiBvIHZlbnRhIGNvbXBhcnRpZG9zIHBvciBlbCBzb2NpbyBmb3JtYWRvciwgc2Vyw61hIHBvc2libGUgcmVhbGl6YXIgbG8gc29saWNpdGFkbyB5IGNyZWFyIHVuYSBiYXNlIGRlIGRhdG9zIG1hZXN0cmEgcXVlIHVuaWZpcXVlIHRhbnRvIGxvcyBmYWN0b3JlcyBleHRlcm5vcyBjb21vIGludGVybm8uCgojIyMgRGlzZcOxbyBkZSBCYXNlcwpEaXNlw7FhciB5IG9yZ2FuaXphciBiYXNlKHMpIGRlIGRhdG9zIGEgcGFydGlyIGRlIGxhIGluZm9ybWFjacOzbiB5IGRhdG9zIHNlbGVjY2lvbmFkb3MuCgojIyMjICoqU2l0dWFjacOzbiBQcm9ibGVtYSAxOiBFbmZvcXVlIGVuIENhcGl0YWwgSHVtYW5vKioKClBhcmEgYWJvcmRhciBsb3MgZGVzYWbDrW9zIGFzb2NpYWRvcyBhbCBjYXBpdGFsIGh1bWFubywgc2UgcHJvcG9uZSBsYSBzaWd1aWVudGUgZXN0cnVjdHVyYSB5IG9yZ2FuaXphY2nDs24gZGUgbGFzIGJhc2VzIGRlIGRhdG9zOgoKLSAqKkJhc2UgZGUgRGF0b3MgYEZPUk1fQmFqYXNgKio6IEVzdGEgYmFzZSBzZSBlbmZvY2Fyw6EgZW4gcmVjb3BpbGFyIGluZm9ybWFjacOzbiBkZXRhbGxhZGEgc29icmUgbGFzIGJhamFzIGRlIHBlcnNvbmFsLCBpbmNsdXllbmRvIG1vdGl2b3MgZGUgc2FsaWRhLCBmZWNoYXMgZGUgYmFqYSwgZHVyYWNpw7NuIGRlbCBlbXBsZW8sIHkgY3VhbHF1aWVyIGRhdG8gcmVsZXZhbnRlIHF1ZSBwdWVkYSBpbmZsdWlyIGVuIGxhIGRlY2lzacOzbiBkZSBkZWphciBsYSBlbXByZXNhLiBTZSBidXNjYXLDoSBpZGVudGlmaWNhciBwYXRyb25lcyBxdWUgcHVlZGFuIHByZXZlbmlyIGZ1dHVyYXMgYmFqYXMuCiAgCi0gKipCYXNlIGRlIERhdG9zIGBGT1JNX1NhdGlzZmFjY2lvbmAqKjogQ29udGVuZHLDoSByZXN1bHRhZG9zIGRlIGVuY3Vlc3RhcyBkZSBzYXRpc2ZhY2Npw7NuIGxhYm9yYWwsIGZlZWRiYWNrIHNvYnJlIGVsIGFtYmllbnRlIGxhYm9yYWwsIG9wb3J0dW5pZGFkZXMgZGUgY3JlY2ltaWVudG8sIGJhbGFuY2UgZW50cmUgdmlkYSBsYWJvcmFsIHkgcGVyc29uYWwsIHkgb3Ryb3MgZmFjdG9yZXMgcXVlIGFmZWN0YW4gbGEgc2F0aXNmYWNjacOzbiB5IHJldGVuY2nDs24gZGVsIHBlcnNvbmFsLiBFc3RhIGJhc2Ugc2UgdXRpbGl6YXLDoSBwYXJhIGFuYWxpemFyIGNvcnJlbGFjaW9uZXMgZW50cmUgc2F0aXNmYWNjacOzbiB5IHByb2R1Y3RpdmlkYWQgbyBwZXJtYW5lbmNpYSBlbiBsYSBlbXByZXNhLgoKUGFyYSBhbWJhcyBiYXNlcywgc2UgcmVhbGl6YXLDoSB1biB0cmFiYWpvIGRlIGxpbXBpZXphIGRlIGRhdG9zLCBub3JtYWxpemFjacOzbiB5IHVuaWZpY2FjacOzbiBkZSBmb3JtYXRvcyBwYXJhIGFzZWd1cmFyIGNvaGVyZW5jaWEgeSBmYWNpbGl0YXIgZWwgYW7DoWxpc2lzLiBBZGVtw6FzLCBzZSBpbnRlZ3JhcsOhIGxhIGJhc2UgZGUgZGF0b3MgZGUgcG9sw61nb25vcyBkZWwgR29iaWVybm8gZGUgTcOpeGljbyBwYXJhIHJlYWxpemFyIGFuw6FsaXNpcyBlc3BhY2lhbCwgcGVybWl0aWVuZG8gZXhwbG9yYXIgbGEgZGlzdHJpYnVjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgYmFqYXMgeSBsYSBzYXRpc2ZhY2Npw7NuIGRlbCBwZXJzb25hbCwgeSBjw7NtbyBlc3RvcyBmYWN0b3JlcyBwdWVkZW4gaW5mbHVpciBlbiBsYSBkaW7DoW1pY2EgZGUgdHJhYmFqby4KCiMjIyMgKipTaXR1YWNpw7NuIFByb2JsZW1hIDI6IEVuZm9xdWUgZW4gRGVtYW5kYSB5IE5lYXJzaG9yaW5nKioKCkxhIGVzdHJ1Y3R1cmFjacOzbiBkZSBsYSBiYXNlIGRlIGRhdG9zIHBhcmEgZXN0YSBzaXR1YWNpw7NuIHByb2JsZW1hIHNlIHJlYWxpemFyw6EgZGUgbGEgc2lndWllbnRlIG1hbmVyYToKCi0gKipCYXNlIGRlIERhdG9zIGRlIE5lYXJzaG9yaW5nIHkgQ29tZXJjaW8gRXh0ZXJpb3IqKjogSW5jbHVpcsOhIGRhdG9zIHNvYnJlIGltcG9ydGFjaW9uZXMsIGV4cG9ydGFjaW9uZXMsIHRlbmRlbmNpYXMgZGUgbmVhcnNob3JpbmcsIHkgY8OzbW8gZXN0b3MgZmFjdG9yZXMgaW1wYWN0YW4gZW4gbGFzIGluZHVzdHJpYXMgcmVsZXZhbnRlcyBwYXJhIGxhIGVtcHJlc2EuIFNlIGRlc2dsb3NhcsOhIHBvciB0aXBvIGRlIHByb2R1Y3RvLCBvcmlnZW4sIGRlc3Rpbm8sIHZvbHVtZW4geSB2YWxvciBkZSBsYXMgdHJhbnNhY2Npb25lcy4KCi0gKipCYXNlIE1hZXN0cmEgSW50ZWdyYWRhKio6IEEgcGFydGlyIGRlIGxvcyBkYXRvcyBkZSBuZWFyc2hvcmluZyB5IGNvbWVyY2lvIGV4dGVyaW9yLCBzZSBidXNjYXLDoSBpbnRlZ3JhciBlc3RhIGluZm9ybWFjacOzbiBjb24gZGF0b3MgaW50ZXJub3MgZGUgcHJvZHVjY2nDs24sIHZlbnRhcywgeSBjdWFscXVpZXIgb3RybyBkYXRvIHJlbGV2YW50ZSBwcm9wb3JjaW9uYWRvIHBvciBlbCBzb2NpbyBmb3JtYWRvci4gRXN0YSBiYXNlIG1hZXN0cmEgcGVybWl0aXLDoSBhbmFsaXphciBsYSBkZW1hbmRhIGRlc2RlIHVuYSBwZXJzcGVjdGl2YSBpbnRlcm5hIHkgZXh0ZXJuYSwgZmFjaWxpdGFuZG8gbGEgY3JlYWNpw7NuIGRlIG1vZGVsb3MgcHJlZGljdGl2b3MuCgpQYXJhIGFtYmFzIHNpdHVhY2lvbmVzLCBzZSBhZG9wdGFyw6FuIHByw6FjdGljYXMgZGUgZ2VzdGnDs24gZGUgZGF0b3MgcXVlIGluY2x1eWVuIGxhIGluZGV4YWNpw7NuIGFkZWN1YWRhLCBsYSBpbXBsZW1lbnRhY2nDs24gZGUgY2xhdmVzIGZvcsOhbmVhcyBwYXJhIG1hbnRlbmVyIGxhIGludGVncmlkYWQgcmVmZXJlbmNpYWwsIHkgbGEgY3JlYWNpw7NuIGRlIHZpc3RhcyBvIHRhYmxhcyBhZ3JlZ2FkYXMgcGFyYSBhbsOhbGlzaXMgZXNwZWPDrWZpY29zLiBBZGVtw6FzLCBzZSBwcmVzdGFyw6EgZXNwZWNpYWwgYXRlbmNpw7NuIGEgbGEgc2VndXJpZGFkIHkgcHJpdmFjaWRhZCBkZSBsb3MgZGF0b3MsIGFzZWd1cmFuZG8gcXVlIGxhIGluZm9ybWFjacOzbiBzZW5zaWJsZSBzZWEgbWFuZWphZGEgY29uZm9ybWUgYSBsYXMgbm9ybWF0aXZhcyBhcGxpY2FibGVzLgoKIyMjIEJhc2VzIE1hZXN0cmFzClZpc3VhbGl6YXIgZW4gUiBsb3MgcHJpbWVyb3MgNiByZW5nbG9uZXMgZGUgbGEgbnVldmEgYmFzZSBkZSBkYXRvcy4KCiMjIyMjIEJhc2UgZGUgRGF0b3M6IEJhamFzIEZPUk0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kc2V0d2QoIi4uL2RhdGFiYXNlcyIpCmJhamFzIDwtIHJlYWRfeGxzeCgiZm9ybS9mb3JtLWJhamFzLnhsc3giKQpoZWFkKGJhamFzKQpgYGAKCiMjIyMjIEJhc2UgZGUgRGF0b3M6IFNhdGlzZmFjY2nDs24gRk9STQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpzZXR3ZCgiLi4vZGF0YWJhc2VzIikKc2F0aXMgPC0gcmVhZF94bHN4KCJmb3JtL0VuY3Vlc3RhX0RhdG9zX0ZPUk1fRmFsbDIwMjMueGxzeCIpCmhlYWQoc2F0aXMpCmBgYAoKIyMjIyMgQmFzZSBkZSBEYXRvczogTmVhcnNob3JpbmcKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kc2V0d2QoIi4uL2RhdGFiYXNlcyIpCm5lYXJzaG9yaW5nIDwtIHJlYWRfeGxzeCgibmVhcnNob3JpbmcvYW5udWFsX2Vjb25vbWljX2RhdGEueGxzeCIpCnRhaWwobmVhcnNob3JpbmcpCmBgYAoKIyMjIyMgQmFzZSBkZSBEYXRvczogRXhwb3J0YWNpw7NuIGRlIFZlaGljdWxvcwpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpzZXR3ZCgiLi4vZGF0YWJhc2VzIikKZXhwb3J0IDwtIHJlYWRfY3N2KCJpbmR1c3RyeV9hdXRvc19teC9leHBvcnRhY2lvbl92ZWhpY3Vsb3NfbXguY3N2IikKaGVhZChleHBvcnQpCmBgYAoKIyMjIEdsb3NhcmlvIGRlIFZhcmlhYmxlcwpFbGFib3JhciBnbG9zYXJpbyBkZSBsYXMgdmFyaWFibGVzIHF1ZSBzZSBpbmNsdXllbiBlbiBsYSBudWV2YSBiYXNlIGRlIGRhdG9zLgoKIyMjIEdsb3NhcmlvIGRlIFZhcmlhYmxlcwoKRWxhYm9yYWNpw7NuIGRlIHVuIGdsb3NhcmlvIHBhcmEgbGFzIHZhcmlhYmxlcyBpbmNsdWlkYXMgZW4gbGFzIG51ZXZhcyBiYXNlcyBkZSBkYXRvcywgc2luIGluY2x1aXIgZWwgdGlwbyBkZSBkYXRvLgoKIyMjIyBCYXNlIGRlIERhdG9zOiBCYWphcyBGT1JNCgotICoqTW90aXZvIGRlIEJhamEqKjogUmF6w7NuIHBvciBsYSBjdWFsIGVsIGVtcGxlYWRvIGRlasOzIGxhIGVtcHJlc2EuCi0gKipQdWVzdG8qKjogQ2FyZ28gcXVlIGVsIGVtcGxlYWRvIG9jdXBhYmEgZW4gbGEgZW1wcmVzYS4KLSAqKkRwdG8qKjogRGVwYXJ0YW1lbnRvIGFsIHF1ZSBwZXJ0ZW5lY8OtYSBlbCBlbXBsZWFkby4KLSAqKlNEKio6IFNhbGFyaW8gZGlhcmlvIGRlbCBlbXBsZWFkby4KLSAqKkVzdGFkbyBDaXZpbCoqOiBFc3RhZG8gY2l2aWwgZGVsIGVtcGxlYWRvIGFsIG1vbWVudG8gZGUgbGEgYmFqYS4KLSAqKkfDqW5lcm8qKjogR8OpbmVybyBkZWwgZW1wbGVhZG8uCi0gKipBw7FvKio6IEHDsW8gZW4gcXVlIHNlIHByb2R1am8gbGEgYmFqYS4KLSAqKkVzdGFkbyoqOiBFc3RhZG8gZGUgbGEgcmVww7pibGljYSBkb25kZSByZXNpZMOtYSBlbCBlbXBsZWFkby4KLSAqKk11bmljaXBpbyoqOiBNdW5pY2lwaW8gZGUgcmVzaWRlbmNpYSBkZWwgZW1wbGVhZG8uCi0gKipEaWFzX3RyYWJhamFkb3MqKjogVG90YWwgZGUgZMOtYXMgcXVlIGVsIGVtcGxlYWRvIHRyYWJhasOzIGVuIGxhIGVtcHJlc2EuCi0gKipNZXNlcyoqOiBOw7ptZXJvIGRlIG1lc2VzIHF1ZSBlbCBlbXBsZWFkbyBlc3R1dm8gZW4gbGEgZW1wcmVzYS4KLSAqKkVkYWQqKjogRWRhZCBkZWwgZW1wbGVhZG8gYWwgbW9tZW50byBkZSBsYSBiYWphLgoKIyMjIyBCYXNlIGRlIERhdG9zOiBTYXRpc2ZhY2Npw7NuIEZPUk0KCi0gKipFbmN1ZXN0YSoqOiBJZGVudGlmaWNhZG9yIMO6bmljbyBkZSBsYSBlbmN1ZXN0YSBkZSBzYXRpc2ZhY2Npw7NuLgotICoqUHVlc3RvKio6IENhcmdvIHF1ZSBvY3VwYSBlbCBlbXBsZWFkbyBkZW50cm8gZGUgbGEgZW1wcmVzYS4KLSAqKkFudGlnw7xlZGFkKio6IFRpZW1wbyAoZW4gYcOxb3MpIHF1ZSBlbCBlbXBsZWFkbyBsbGV2YSB0cmFiYWphbmRvIGVuIGxhIGVtcHJlc2EuCi0gKipSYXpvbl9lbnRyYWRhKio6IE1vdGl2byBwcmluY2lwYWwgcG9yIGVsIHF1ZSBlbCBlbXBsZWFkbyBkZWNpZGnDsyBpbmdyZXNhciBhIGxhIGVtcHJlc2EuCi0gKipTYWxhcmlvX2J1ZW5vKio6IFBlcmNlcGNpw7NuIGRlbCBlbXBsZWFkbyBzb2JyZSBsYSBjb21wZXRpdGl2aWRhZCBkZSBzdSBzYWxhcmlvLgotICoqUHJlc3RhY2lvbmVzX2J1ZW5vKio6IFZhbG9yYWNpw7NuIGRlbCBlbXBsZWFkbyBzb2JyZSBsYXMgcHJlc3RhY2lvbmVzIG9mcmVjaWRhcyBwb3IgbGEgZW1wcmVzYS4KLSAqKkpvcm5hZGFfbm9fZXhjZXNpdmEqKjogT3BpbmnDs24gZGVsIGVtcGxlYWRvIHNvYnJlIGxhIGR1cmFjacOzbiBkZSBzdSBqb3JuYWRhIGxhYm9yYWwuCi0gKipPZnJlY2ltaWVudG9faGVycmFtaWVudGFzKio6IFNpIGVsIGVtcGxlYWRvIGNvbnNpZGVyYSBxdWUgc2UgbGUgcHJvcG9yY2lvbmFuIGxhcyBoZXJyYW1pZW50YXMgbmVjZXNhcmlhcyBwYXJhIHN1IHRyYWJham8uCi0gKipOb19tb2xlc3RpYV90ZW1wZXJhdHVyYSoqOiBDb25mb3J0IHTDqXJtaWNvIGVuIGVsIGx1Z2FyIGRlIHRyYWJham8uCi0gKipFc3RyZXNfYmFqbyoqOiBQZXJjZXBjacOzbiBkZWwgZW1wbGVhZG8gc29icmUgbG9zIG5pdmVsZXMgZGUgZXN0csOpcyBlbiBzdSB0cmFiYWpvLgotICoqRmFjaWxpZGFkX3RyYW5zcG9ydGUqKjogRmFjaWxpZGFkIHBhcmEgdHJhc2xhZGFyc2UgYWwgbHVnYXIgZGUgdHJhYmFqby4KLSAqKlpvbmFfdHJhYmFqb19jb21vZGEqKjogQ29tb2RpZGFkIGRlIGxhIHpvbmEgZGUgdHJhYmFqby4KLSAqKlBlcm1hbmVuY2lhX2Zvcm1fZnV0dXJvKio6IEludGVuY2nDs24gZGVsIGVtcGxlYWRvIGRlIHBlcm1hbmVjZXIgZW4gbGEgZW1wcmVzYSBhIGZ1dHVyby4KLSAqKlN1ZnJpZG9fc2l0dWFjaW9uZXNfY29uZmxpY3RvKio6IFNpIGVsIGVtcGxlYWRvIGhhIGV4cGVyaW1lbnRhZG8gc2l0dWFjaW9uZXMgZGUgY29uZmxpY3RvIGVuIGVsIHRyYWJham8uCi0gKipNb2xlc3RpYXNfcHVlc3RvKio6IEluY29tb2RpZGFkZXMgZsOtc2ljYXMgcmVsYWNpb25hZGFzIGNvbiBlbCBwdWVzdG8gZGUgdHJhYmFqby4KLSAqKlNlbnRpbWllbnRvX2Zvcm0qKjogU2VudGltaWVudG9zIGdlbmVyYWxlcyBkZWwgZW1wbGVhZG8gaGFjaWEgbGEgZW1wcmVzYS4KLSAqKkVkYWQqKjogRWRhZCBkZWwgZW1wbGVhZG8uCi0gKipHw6luZXJvKio6IEfDqW5lcm8gZGVsIGVtcGxlYWRvLgotICoqRXN0YWRvIENpdmlsKio6IEVzdGFkbyBjaXZpbCBkZWwgZW1wbGVhZG8uCi0gKipNdW5pY2lwaW8qKjogTXVuaWNpcGlvIGRlIHJlc2lkZW5jaWEgZGVsIGVtcGxlYWRvLgotICoqTml2ZWxfZXNjb2xhcioqOiDDmmx0aW1vIG5pdmVsIGRlIGVzdHVkaW9zIGNvbXBsZXRhZG8gcG9yIGVsIGVtcGxlYWRvLgotICoqUGVyc29uYXNfZGVwZW5kaWVudGVzKio6IE7Dum1lcm8gZGUgcGVyc29uYXMgcXVlIGRlcGVuZGVuIGVjb27Ds21pY2FtZW50ZSBkZWwgZW1wbGVhZG8uCgojIyMjIEJhc2UgZGUgRGF0b3M6IE5lYXJzaG9yaW5nCgotICoqQcOxbyoqOiBBw7FvIGRlIHJlZ2lzdHJvIGRlIGxhIGluZm9ybWFjacOzbi4KLSAqKklFRF9GbHVqb3NfUmVhbGVzKio6IEludmVyc2nDs24gRXh0cmFuamVyYSBEaXJlY3RhIGVuIGZsdWpvcyByZWFsZXMuCi0gKipFeHBvcnRhY2lvbmVzKio6IFZhbG9yIHRvdGFsIGRlIGxhcyBleHBvcnRhY2lvbmVzIHJlYWxpemFkYXMuCi0gKipFZHVjYWNpb24qKjogSW5kaWNhZG9yZXMgcmVsYWNpb25hZG9zIGNvbiBsYSBlZHVjYWNpw7NuLgotICoqU2FsYXJpb19EaWFyaW8qKjogU2FsYXJpbyBkaWFyaW8gcHJvbWVkaW8uCi0gKipJbm5vdmFjaW9uKio6IEluZGljYWRvcmVzIGRlIGlubm92YWNpw7NuIHkgZGVzYXJyb2xsbyB0ZWNub2zDs2dpY28uCi0gKipJbnNlZ3VyaWRhZF9Sb2JvKio6IMONbmRpY2VzIGRlIHJvYm9zLgotICoqSW5zZWd1cmlkYWRfSG9taWNpZGlvKio6IMONbmRpY2VzIGRlIGhvbWljaWRpb3MuCi0gKipUaXBvX2RlX0NhbWJpbyoqOiBWYWxvciBkZWwgdGlwbyBkZSBjYW1iaW8uCi0gKipEZW5zaWRhZF9DYXJyZXRlcmEqKjogRGVuc2lkYWQgZGUgbGEgcmVkIGNhcnJldGVyYS4KLSAqKkRlbnNpZGFkX1BvYmxhY2lvbioqOiBEZW5zaWRhZCBwb2JsYWNpb25hbC4KLSAqKlBJQl9QZXJfQ2FwaXRhKio6IFByb2R1Y3RvIEludGVybm8gQnJ1dG8gcGVyIGPDoXBpdGEuCi0gKipJTlBDKio6IMONbmRpY2UgTmFjaW9uYWwgZGUgUHJlY2lvcyBhbCBDb25zdW1pZG9yLgotICoqRW1wbGVvKio6IEluZGljYWRvcmVzIGRlIGVtcGxlby4KLSAqKkNPMl9FbWlzaW9uZXMqKjogRW1pc2lvbmVzIGRlIENPMi4KLSAqKkVtcHJlc2FzX0V4dHJhbmplcmFzX1JlZ2lzdHJhZGFzKio6IE7Dum1lcm8gZGUgZW1wcmVzYXMgZXh0cmFuamVyYXMgcmVnaXN0cmFkYXMuCi0gKipQb2JsYWNpw7NuX0Vjb25vbWljYW1lbnRlX0FjdGl2YSoqOiBQb2JsYWNpw7NuIGVjb27Ds21pY2FtZW50ZSBhY3RpdmEuCi0gKipQb2JsYWNpb25fb2N1cGFkYV9pbmR1c3RyaWFfbWFudWZhY3R1cmVyYSoqOiBQb2JsYWNpw7NuIG9jdXBhZGEgZW4gbGEgaW5kdXN0cmlhIG1hbnVmYWN0dXJlcmEuCi0gKipQb2JsYWNpb25fb2N1cGFkYSoqOiBQb2JsYWNpw7NuIG9jdXBhZGEgZW4gZ2VuZXJhbC4KLSAqKlRhc2FfZGVfb2N1cGFjaW9uX2luZHVzdHJpYV9tYW51ZmFjdHVyZXJhKio6IFRhc2EgZGUgb2N1cGFjacOzbiBlbiBsYSBpbmR1c3RyaWEgbWFudWZhY3R1cmVyYS4KCgojIyBBbsOhbGlzaXMgRXhwbG9yYXRvcmlvIGRlIGxvcyBEYXRvcyAoRURBKQpEZXNhcnJvbGxhciBFREEgcXVlIHJlc3BvbmRhIGNhZGEgdW5hIGRlIGxhcyBwcmVndW50YXMgZGUgYW7DoWxpc2lzLgoKIyMjIyBJbXBvcnRhbmRvIGJhc2VzIGRlIGRhdG9zCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnNldHdkKCIuLi9kYXRhYmFzZXMvIikKZGF0b3MgPC0gcmVhZF9leGNlbCgiZm9ybS9FbmN1ZXN0YV9EYXRvc19GT1JNX0ZhbGwyMDIzLnhsc3giKQpkZiA9IHJlYWRfeGxzeCgiZm9ybS90ZW1wb3JhcnkvQkREX0ZPUk1fQkFKQVMtMjAyMy54bHN4IikKCmRhdG9zX251bSA8LSBkYXRvcwpkYXRvc19udW1bc2FwcGx5KGRhdG9zX251bSwgaXMuZmFjdG9yKV0gPC0gbGFwcGx5KGRhdG9zX251bVtzYXBwbHkoZGF0b3NfbnVtLCBpcy5mYWN0b3IpXSwgYXMubnVtZXJpYykKYGBgCgojIyMgKiphLiBFc3RhZMOtc3RpY29zIERlc2NyaXB0aXZvcyoqCgojIyMjICoqQW5hbGlzaXMgZGUgRW5jdWVzdGEgZGUgU2F0aXNmYWNjacOzbioqCgojIyMjIyBFc3RydWN0dXJhIGRlIGxhIGJhc2UgZGUgZGF0b3MKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kc3RyKGRhdG9zX251bSkKYGBgCgojIyMjIyBNZWRpZGFzIERlc2NyaXB0aXZhcwpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpzdW1tYXJ5KGRhdG9zX251bSkKYGBgCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpkZXNjcmliZShkYXRvc19udW0pCmBgYAoKIyMjICAqKmIuIE1lZGlkYXMgZGUgRGlzcGVyc2nDs24qKgoKIyMjIyMgTWVkaWRhcyBkZSBEaXNwZXJzacOzbgoKKipDw6FsY3VsbyBkZSBtZWRpZGFzIGRlIGRpc3BlcnNpw7NuIHBhcmEgY2FkYSB2YXJpYWJsZSBudW3DqXJpY2EgcmVsZXZhbnRlKioKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kc2FwcGx5KGRhdG9zX251bSwgdmFyLCBuYS5ybSA9IFRSVUUpICAjIFZhcmlhbnphCnNhcHBseShkYXRvc19udW0sIHNkLCBuYS5ybSA9IFRSVUUpICAgIyBEZXN2aWFjacOzbiBlc3TDoW5kYXIKYGBgCgoqKkPDoWxjdWxvIGRlbCByYW5nbyBpbnRlcmN1YXJ0w61saWNvIHBhcmEgY2FkYSB2YXJpYWJsZSBudW3DqXJpY2EgcmVsZXZhbnRlKioKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kc2FwcGx5KGRhdG9zX251bSwgSVFSLCBuYS5ybSA9IFRSVUUpCmBgYAoKIyMjICoqYy4gNC02IEdyw6FmaWNvcyAoYmFycmFzLCBsw61uZWFzLCBwYXN0ZWwsIGRpc3BlcnNpw7NuLCBidXJidWphcywgY29ycmVsYWNpw7NuLCBtYXBhcykqKgoKIyMjIyMgKipSZWxhY2nDs24gZW50cmUgZWwgTml2ZWwgZGUgRXN0csOpcyB5IFB1ZXN0byBkZSBUcmFiYWpvKioKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2dwbG90KGRhdG9zLCBhZXMoeCA9IHJlb3JkZXIocHVlc3RvLCBlc3RyZXNfYmFqbywgRlVOID0gbWVkaWFuKSwgeSA9IGVzdHJlc19iYWpvKSkgKwogIGdlb21fYmFyKHN0YXQgPSAic3VtbWFyeSIsIGZ1biA9ICJtZWRpYW4iLCBmaWxsID0gIm9yYW5nZSIsIGNvbG9yID0gImJsYWNrIikgKwogIGNvb3JkX2ZsaXAoKSArICAjIEludmVydGlyIGVqZXMgcGFyYSB0ZW5lciBsb3MgcHVlc3RvcyBlbiBlbCBlamUgeSB5IGxhcyBiYXJyYXMgZXh0ZW5kacOpbmRvc2UgaG9yaXpvbnRhbG1lbnRlCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIk5pdmVsIGRlIEVzdHLDqXMgY29uIGJhc2UgZW4gTWVkaWEgcG9yIFB1ZXN0byBkZSBUcmFiYWpvIiwKICAgICAgIHkgPSAiTml2ZWwgZGUgRXN0csOpcyBNZWRpYW5vIiwKICAgICAgIHggPSAiUHVlc3RvIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCmBgYAoKRW4gZXN0YSBncsOhZmljYSBkZSBiYXJyYXMgcG9kZW1vcyBvYnNlcnZhciBkaWZlcmVudGVzIHB1ZXN0b3MgZGUgdHJhYmFqbyB5IHN1IGNvcnJlc3BvbmRpZW50ZSBuaXZlbCBtZWRpYW5vIGRlIGVzdHLDqXMuCgpMb3MgcHVlc3RvcyBjb24gbml2ZWxlcyBtw6FzIGFsdG9zIGRlIGVzdHLDqXMgcGFyZWNlbiBzZXIgc29sZGFkb3Isb3RybywgeSBvcGVyYWRvci4KVW4gaGFsbGF6Z28gaW1wb3J0YW50ZSBlcyBxdWUgZXN0b3MgcHVlc3RvcyBwdWVkZW4gdGVuZXIgY29uZGljaW9uZXMgZGUgdHJhYmFqbyBxdWUgZ2VuZXJhbiB1biBhbHRvIG5pdmVsIGRlIGVzdHLDqXMsIGxvIHF1ZSBwb2Ryw61hIGVzdGFyIGNvbnRyaWJ1eWVuZG8gYSBsYSByb3RhY2nDs24gZGUgcGVyc29uYWwuIExhIGVtcHJlc2EgRk9STSBwb2Ryw61hIGVuZm9jYXJzZSBlbiBtZWpvcmFyIGxhcyBjb25kaWNpb25lcyBkZSB0cmFiYWpvIGVuIGVzdG9zIHB1ZXN0b3MsIHRhbCB2ZXogYXV0b21hdGl6YW5kbyB0YXJlYXMgZXN0cmVzYW50ZXMgbyBwcm9wb3JjaW9uYW5kbyBtw6FzIGFwb3lvIHkgZGVzY2Fuc29zLgoKTG9zIHB1ZXN0b3MgY29uIG1lbm9yZXMgbml2ZWxlcyBkZSBlc3Ryw6lzIHNvbiBhc2lzdGVudGUgZGUgcHJvZHVjY2nDs24sZW1iYXJxdWUsIHkgbWFudGVuaW1pZW50bywgbG8gcXVlIHBvZHLDrWEgaW5kaWNhciBxdWUgZXN0YXMgw6FyZWFzIHNvbiBtZW5vcyBwcm9wZW5zYXMgYSBleHBlcmltZW50YXIgcm90YWNpw7NuIGRlYmlkbyBhbCBlc3Ryw6lzIGxhYm9yYWwuCgojIyMjIyAqKlJlbGFjacOzbiBlbnRyZSBsYSBBbnRpZ8O8ZWRhZCB5IGVsIFNhbGFyaW8qKgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KYW50aWd1ZWRhZF9wb3Jfc2FsYXJpbyA8LSBkYXRvcyAlPiUKICBncm91cF9ieShzYWxhcmlvX2J1ZW5vKSAlPiUKICBzdW1tYXJpc2UoYW50aWd1ZWRhZF9wcm9tZWRpbyA9IG1lYW4oYW50aWd1ZWRhZCwgbmEucm0gPSBUUlVFKSkgJT4lCiAgYXJyYW5nZShkZXNjKGFudGlndWVkYWRfcHJvbWVkaW8pKQoKIyBEZWZpbmlyIHVuYSBwYWxldGEgZGUgY29sb3JlcyBwZXJzb25hbGl6YWRhCmNvbG9yZXNfcGVyc29uYWxpemFkb3MgPC0gYygnVG90YWxtZW50ZSBkZSBhY3VlcmRvJyA9ICcjQUVENkYxJywgIyBDbGFybwogICAgICAgICAgICAgICAgICAgICAgICAgICAgJ01lZGlhbmFtZW50ZSBkZSBhY3VlcmRvJyA9ICcjNURBREUyJywgIyBJbnRlcm1lZGlvIGNsYXJvCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnTmkgZGUgYWN1ZXJkbyBuaSBlbiBkZXNhY3VlcmRvJyA9ICcjMzQ5OERCJywgIyBOZXV0cm8KICAgICAgICAgICAgICAgICAgICAgICAgICAgICdNZWRpYW5hbWVudGUgZW4gZGVzYWN1ZXJkbycgPSAnIzI4NzRBNicsICMgSW50ZXJtZWRpbyBvc2N1cm8KICAgICAgICAgICAgICAgICAgICAgICAgICAgICdUb3RhbG1lbnRlIGVuIGRlc2FjdWVyZG8nID0gJyMxQjRGNzInKSAjIE9zY3VybwoKIyBHcsOhZmljbyBkZSBiYXJyYXMgZGUgbGEgYW50aWfDvGVkYWQgcHJvbWVkaW8gcG9yIHNhdGlzZmFjY2nDs24gY29uIGVsIHNhbGFyaW8sIHVzYW5kbyBjb2xvcmVzIHBlcnNvbmFsaXphZG9zCmdncGxvdChhbnRpZ3VlZGFkX3Bvcl9zYWxhcmlvLCBhZXMoeCA9IHNhbGFyaW9fYnVlbm8sIHkgPSBhbnRpZ3VlZGFkX3Byb21lZGlvLCBmaWxsID0gc2FsYXJpb19idWVubykpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbG9yZXNfcGVyc29uYWxpemFkb3MpICsgIyBVc2EgbGEgcGFsZXRhIGRlIGNvbG9yZXMgcGVyc29uYWxpemFkYQogIGNvb3JkX2ZsaXAoKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIkFudGlnw7xlZGFkIFByb21lZGlvIHBvciBTYXRpc2ZhY2Npw7NuIGNvbiBlbCBTYWxhcmlvIiwKICAgICAgIHggPSAiU2F0aXNmYWNjacOzbiBjb24gZWwgU2FsYXJpbyIsCiAgICAgICB5ID0gIkFudGlnw7xlZGFkIFByb21lZGlvIChhw7FvcykiCikKYGBgCgpFc3RhIGdyw6FmaWNhIGRlIGJhcnJhcyB2ZXJ0aWNhbGVzIGlsdXN0cmEgbGEgcmVsYWNpw7NuIGVudHJlIGxhIGFudGlnw7xlZGFkIHByb21lZGlvIGVuIGxhIGVtcHJlc2EgeSBlbCBncmFkbyBkZSBzYXRpc2ZhY2Npw7NuIGNvbiBlbCBzYWxhcmlvLiBTZSBvYnNlcnZhIHVuYSBjb3JyZWxhY2nDs24gcG9zaXRpdmEgZW50cmUgbGEgYW50aWfDvGVkYWQgeSBsYSBzYXRpc2ZhY2Npw7NuIHNhbGFyaWFsLCBkZXN0YWNhbmRvIHF1ZSBsb3MgZW1wbGVhZG9zIHF1ZSBlc3TDoW4gdG90YWxtZW50ZSBzYXRpc2ZlY2hvcyBjb24gc3Ugc2FsYXJpbyB0aWVuZGVuIGEgdGVuZXIgdW5hIG1heW9yIGFudGlnw7xlZGFkLCBlc3BlY8OtZmljYW1lbnRlIGVudHJlIDE1IGEgMjAgYcOxb3MuCgpFc3RlIHBhdHLDs24gc3VnaWVyZSBxdWUgbGEgc2F0aXNmYWNjacOzbiBzYWxhcmlhbCBpbmNyZW1lbnRhIGNvbiBlbCB0aWVtcG8gZGUgc2VydmljaW8gZW4gbGEgZW1wcmVzYS4gRXN0byBwb2Ryw61hIGludGVycHJldGFyc2UgY29tbyB1bmEgc2XDsWFsIGRlIHF1ZSBsb3MgYXVtZW50b3Mgc2FsYXJpYWxlcyBvIGJvbmlmaWNhY2lvbmVzIGJhc2FkYXMgZW4gbGEgYW50aWfDvGVkYWQgc29uIGVmZWN0aXZvcywgbyBiaWVuLCBxdWUgbG9zIGVtcGxlYWRvcyBkZSBtYXlvciBhbnRpZ8O8ZWRhZCBvY3VwYW4gcHVlc3RvcyBjb24gbWVqb3IgcmVtdW5lcmFjacOzbiwgcG9zaWJsZW1lbnRlIGRlYmlkbyBhIGFzY2Vuc29zIG8gaW5jcmVtZW50b3Mgc2FsYXJpYWxlcyB2aW5jdWxhZG9zIGEgc3UgZGVzZW1wZcOxbyBhIGxvIGxhcmdvIGRlIGxvcyBhw7Fvcy4KCkFudGUgZXN0b3MgaGFsbGF6Z29zLCBzZSByZWNvbWllbmRhIGEgbGEgZW1wcmVzYSBGT1JNIGNvbnNpZGVyYXIgbW9kaWZpY2FjaW9uZXMgZW4gc3UgZXN0cnVjdHVyYSBzYWxhcmlhbCBwYXJhIGluY3JlbWVudGFyIGxhIHNhdGlzZmFjY2nDs24gc2FsYXJpYWwgZW50cmUgbG9zIGVtcGxlYWRvcyBkZSBtZW5vciBhbnRpZ8O8ZWRhZC4gVGFsIGFqdXN0ZSBwb2Ryw61hIGNvbnRyaWJ1aXIgYSByZWR1Y2lyIGxhIHJvdGFjacOzbiBkZSBwZXJzb25hbCwgZm9tZW50YW5kbyB1biBhbWJpZW50ZSBsYWJvcmFsIG3DoXMgZXN0YWJsZSB5IGNvbXByb21ldGlkby4KCiMjIyMjICoqUGVyY2VwY2nDs24gZGUgTW9sZXN0aWEgcG9yIGxhIFRlbXBlcmF0dXJhIHBvciBQdWVzdG8qKgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGF0b3MgJT4lCiAgZ3JvdXBfYnkocHVlc3RvLCBub19tb2xlc3RpYV90ZW1wZXJhdHVyYSkgJT4lCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBwdWVzdG8sIHkgPSBjb3VudCwgZmlsbCA9IG5vX21vbGVzdGlhX3RlbXBlcmF0dXJhKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBsYWJzKHRpdGxlID0gIlBlcmNlcGNpw7NuIGRlIE1vbGVzdGlhIHBvciBsYSBUZW1wZXJhdHVyYSBwb3IgUHVlc3RvIiwKICAgICAgIHggPSAiUHVlc3RvIiwKICAgICAgIHkgPSAiQ2FudGlkYWQiLAogICAgICAgZmlsbCA9ICJObyBNb2xlc3RhIGxhIFRlbXBlcmF0dXJhIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKCmBgYAoKSGVtb3Mgb2JzZXJ2YWRvIHVuYSBub3RhYmxlIGluY29tb2RpZGFkIGNvbiBsYSB0ZW1wZXJhdHVyYSBwb3IgcGFydGUgZGUgbG9zIGF5dWRhbnRlcyBnZW5lcmFsZXMsIGxvIGN1YWwgcmVxdWllcmUgcXVlIHRvbWVtb3MgbWVkaWRhcyBwYXJhIHJlZ3VsYXIgZWwgY2xpbWEgZW4gZWwgZXNwYWNpbyBkb25kZSBkZXNlbXBlw7FhbiBzdXMgbGFib3Jlcy4gRXN0YSBzaXR1YWNpw7NuIG5vIHBhcmVjZSBzZXIgdGFuIHByb251bmNpYWRhIGVuIG90cmFzIMOhcmVhcy4KCiMjIyMjICoqRGlzY29uZm9ybWlkYWQgcG9yIFB1ZXN0byoqIAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGF0b3MgJT4lIAogIGdyb3VwX2J5KHB1ZXN0bywgcGVybWFuZW5jaWFfZm9ybV9mdXR1cm8pICU+JSAKICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JQogIGZpbHRlcihwZXJtYW5lbmNpYV9mb3JtX2Z1dHVybyAhPSAiVG90YWxtZW50ZSBkZSBhY3VlcmRvIiAmIHBlcm1hbmVuY2lhX2Zvcm1fZnV0dXJvICE9ICJNZWRpYW5hbWVudGUgZGUgYWN1ZXJkbyIpICU+JQogIGdncGxvdChhZXMoeCA9IHJlb3JkZXIocHVlc3RvLCAtY291bnQpLCB5ID0gY291bnQsIGZpbGwgPSBwZXJtYW5lbmNpYV9mb3JtX2Z1dHVybykpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGNvb3JkX2ZsaXAoKSArCiAgbGFicyh0aXRsZSA9ICJEaXNjb25mb3JtaWRhZCBwb3IgUHVlc3RvIiwKICAgICAgIHggPSAiUHVlc3RvIiwKICAgICAgIHkgPSAiQ2FudGlkYWQgZGUgRGlzY29uZm9ybWlkYWQiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKCiMjIyMjICoqUGVyY2VwY2nDs24gZGVsIEVzdHLDqXMgcG9yIFJhbmdvcyBkZSBBbnRpZ8O8ZWRhZCoqCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpkYXRvcyRhbnRpZ3VlZGFkX3JhbmdvIDwtIGN1dChkYXRvcyRhbnRpZ3VlZGFkLCBicmVha3MgPSBzZXEoMCwgbWF4KGRhdG9zJGFudGlndWVkYWQsIG5hLnJtID0gVFJVRSkgKyA1LCBieSA9IDUpLCByaWdodCA9IEZBTFNFLCBsYWJlbHMgPSBwYXN0ZShzZXEoMCwgbWF4KGRhdG9zJGFudGlndWVkYWQsIG5hLnJtID0gVFJVRSksIGJ5ID0gNSksIHNlcSg1LCBtYXgoZGF0b3MkYW50aWd1ZWRhZCwgbmEucm0gPSBUUlVFKSArIDUsIGJ5ID0gNSkgLSAxLCBzZXAgPSAiLSIpKQpgYGAKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRhdG9zICU+JQogIGdyb3VwX2J5KGFudGlndWVkYWRfcmFuZ28sIGVzdHJlc19iYWpvKSAlPiUKICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JQogIGdncGxvdChhZXMoeCA9IGFudGlndWVkYWRfcmFuZ28sIHkgPSBjb3VudCwgZmlsbCA9IGVzdHJlc19iYWpvKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBsYWJzKHRpdGxlID0gIlBlcmNlcGNpw7NuIGRlbCBFc3Ryw6lzIHBvciBSYW5nb3MgZGUgQW50aWfDvGVkYWQiLAogICAgICAgeCA9ICJSYW5nbyBkZSBBbnRpZ8O8ZWRhZCIsCiAgICAgICB5ID0gIkNhbnRpZGFkIiwKICAgICAgIGZpbGwgPSAiUGVyY2VwY2nDs24gZGUgQmFqbyBFc3Ryw6lzIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKCmBgYAoKQ29udGFtb3MgY29uIGluZGljaW9zIHPDs2xpZG9zIGRlIHF1ZSBlbCBlc3Ryw6lzIG5vIGNvbnN0aXR1eWUgdW4gZmFjdG9yIGFkdmVyc28gcGFyYSBudWVzdHJvcyB0cmFiYWphZG9yZXMuIE9ic2VydmFtb3MgcXVlIGxhIG1heW9yw61hLCBzaW4gaW1wb3J0YXIgc3UgdGllbXBvIGRlIHNlcnZpY2lvIGVuIGxhIGVtcHJlc2EsIHJlcG9ydGEgZXhwZXJpbWVudGFyIHVuIG5pdmVsIGJham8gZGUgZXN0csOpcyBlbiBzdXMgYWN0aXZpZGFkZXMgbGFib3JhbGVzLgoKIyMjIyMgICoqUGVyY2VwY2nDs24gZGUgUHJlc3RhY2lvbmVzIHBvciBQdWVzdG8qKgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGF0b3MgJT4lCiAgZ3JvdXBfYnkocHVlc3RvLCBwcmVzdGFjaW9uZXNfYnVlbm8pICU+JQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcHVlc3RvLCB5ID0gY291bnQsIGZpbGwgPSBwcmVzdGFjaW9uZXNfYnVlbm8pKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKwogIGxhYnModGl0bGUgPSAiUGVyY2VwY2nDs24gZGUgUHJlc3RhY2lvbmVzIHBvciBQdWVzdG8iLAogICAgICAgeCA9ICJQdWVzdG8iLAogICAgICAgeSA9ICJDYW50aWRhZCIsCiAgICAgICBmaWxsID0gIkhheSBCdWVuYXMgUHJlc3RhY2lvbmVzIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKYGBgCgpPYnNlcnZhbW9zIHF1ZSBlbnRyZSBsb3MgYXl1ZGFudGVzIGdlbmVyYWxlcyBzZSBjb25jZW50cmEgbGEgbWF5b3IgY2FudGlkYWQgZGUgcmVzcHVlc3RhcyBlbiBudWVzdHJhIGJhc2UgZGUgZGF0b3MsIGxvIGN1YWwgaW5kaWNhIHF1ZSBlc3RlIGdydXBvIGVzIGVsIG3DoXMgbnVtZXJvc28uIERlbnRybyBkZSBlc3RlIGNvbGVjdGl2bywgbGFzIG9waW5pb25lcyBzb2JyZSBsYXMgcHJlc3RhY2lvbmVzIG9mcmVjaWRhcyBwb3IgbGEgZW1wcmVzYSBzb24gdmFyaWFkYXMuIEVzdGUgZmVuw7NtZW5vIHN1Z2llcmUgcXVlIGxvcyBheXVkYW50ZXMgZ2VuZXJhbGVzIG5vIGVzdMOhbiBjb21wbGV0YW1lbnRlIHNhdGlzZmVjaG9zIGNvbiBsYXMgcHJlc3RhY2lvbmVzIHF1ZSByZWNpYmVuOyBkZSBsbyBjb250cmFyaW8sIG5vIG9ic2VydmFyw61hbW9zIHRhbCBkaXZlcnNpZGFkIGVuIGxhcyByZXNwdWVzdGFzLgoKUG9yIHRhbnRvLCBzZSBwdWVkZSBjb25jbHVpciBxdWUgdW5hIGRlIGxhcyBwcmluY2lwYWxlcyDDoXJlYXMgZGUgbWVqb3JhIHBhcmEgbGEgZW1wcmVzYSByZXNpZGUgZW4gZWwgdHJhdG8gaGFjaWEgbG9zIGF5dWRhbnRlcyBnZW5lcmFsZXMsIHF1aWVuZXMgZXhwcmVzYW4gZGVzY29udGVudG8gcHJpbmNpcGFsbWVudGUgY29uIGxhIHRlbXBlcmF0dXJhIGVuIHN1IGx1Z2FyIGRlIHRyYWJham8geSBwZXJjaWJlbiBxdWUgbGFzIHByZXN0YWNpb25lcyBxdWUgcmVjaWJlbiBubyBzb24gYWRlY3VhZGFzLiBFc3RhIHNpdHVhY2nDs24gcG9kcsOtYSBlc3RhciBjb250cmlidXllbmRvIGEgbGEgYWx0YSByb3RhY2nDs24gb2JzZXJ2YWRhIGVuIGVzdGUgc2VjdG9yIGRlIGxhIGVtcHJlc2EuCgojIyMgKipkLiBUYWJsYXMgKGZyZXF1ZW5jaWEsIGNvbnRpbmdlbmNpYSkqKgoKIyMjIyBBbmFsaXNpcyBkZSBCYWphcyBkZSBGT1JNCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpzdW1tYXJ5KGRmKQpgYGAKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRmIDwtIGRmICU+JSAKICBtdXRhdGUoRHB0byA9IGlmX2Vsc2UoRHB0byA9PSAiUHJvZHVjY2lvbiBDYXJ0w7NuIE1DIiwgIlByb2R1Y2Npw7NuIENhcnTDs24gTUMiLCBEcHRvKSkKYGBgCgojIyMjIyAqKkJhamFzIHBvciBEZXBhcnRhbWVudG8qKgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KYmFqYXNfcG9yX2RlcGFydGFtZW50byA8LSBkZiAlPiUKICBncm91cF9ieShEcHRvKSAlPiUKICBzdW1tYXJpc2UoVG90YWxfQmFqYXMgPSBuKCkpCgpnZ3Bsb3QoYmFqYXNfcG9yX2RlcGFydGFtZW50bywgYWVzKHggPSByZW9yZGVyKERwdG8sIC1Ub3RhbF9CYWphcyksIHkgPSBUb3RhbF9CYWphcywgZmlsbCA9IERwdG8pKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiQmFqYXMgcG9yIERlcGFydGFtZW50byIsIHggPSAiRGVwYXJ0YW1lbnRvIiwgeSA9ICJUb3RhbCBkZSBCYWphcyIpCmBgYAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0gCmJhamFzX3Bvcl9kZXBhcnRhbWVudG8gPC0gZGYgJT4lCiAgZ3JvdXBfYnkoRHB0bykgJT4lCiAgc3VtbWFyaXNlKFRvdGFsX0JhamFzID0gbigpKSAlPiUKICBmaWx0ZXIoVG90YWxfQmFqYXMgPiAxKQoKIyBPcmRlbmFtb3MgbGFzIGJhamFzIHBvciBkZXBhcnRhbWVudG8gZGUgbWF5b3IgYSBtZW5vciBlbiBlbCBncsOhZmljbwpnZ3Bsb3QoYmFqYXNfcG9yX2RlcGFydGFtZW50bywgYWVzKHggPSByZW9yZGVyKERwdG8sIC1Ub3RhbF9CYWphcyksIHkgPSBUb3RhbF9CYWphcywgZmlsbCA9IERwdG8pKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiQmFqYXMgcG9yIERlcGFydGFtZW50byAoRmlsdHJhZG8pIiwgeCA9ICJEZXBhcnRhbWVudG8iLCB5ID0gIlRvdGFsIGRlIEJhamFzIikKCmBgYAoKCiMjIyMjICoqQmFqYXMgcG9yIERlcGFydGFtZW50byB5IEfDqW5lcm8qKgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KYmFqYXNfcG9yX2RlcGFydGFtZW50b19nZW5lcm8gPC0gZGYgJT4lCiAgZ3JvdXBfYnkoRHB0bywgR8OpbmVybykgJT4lCiAgc3VtbWFyaXNlKFRvdGFsX0JhamFzID0gbigpKQoKZ2dwbG90KGJhamFzX3Bvcl9kZXBhcnRhbWVudG9fZ2VuZXJvLCBhZXMoeCA9IHJlb3JkZXIoRHB0bywgLVRvdGFsX0JhamFzKSwgeSA9IFRvdGFsX0JhamFzLCBmaWxsID0gR8OpbmVybykpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIkJhamFzIHBvciBEZXBhcnRhbWVudG8geSBHw6luZXJvIiwgeCA9ICJEZXBhcnRhbWVudG8iLCB5ID0gIlRvdGFsIGRlIEJhamFzIikKYGBgCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpiYWphc19wb3JfZGVwYXJ0YW1lbnRvX2dlbmVybyA8LSBkZiAlPiUKICBncm91cF9ieShEcHRvLCBHw6luZXJvKSAlPiUKICBzdW1tYXJpc2UoVG90YWxfQmFqYXMgPSBuKCkpICU+JQogIGZpbHRlcihUb3RhbF9CYWphcyA+IDEpCgpnZ3Bsb3QoYmFqYXNfcG9yX2RlcGFydGFtZW50b19nZW5lcm8sIGFlcyh4ID0gcmVvcmRlcihEcHRvLCAtVG90YWxfQmFqYXMpLCB5ID0gVG90YWxfQmFqYXMsIGZpbGwgPSBHw6luZXJvKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiQmFqYXMgcG9yIERlcGFydGFtZW50byB5IEfDqW5lcm8gKEZpbHRyYWRvKSIsIHggPSAiRGVwYXJ0YW1lbnRvIiwgeSA9ICJUb3RhbCBkZSBCYWphcyIpCgpgYGAKCiMjIyMjICoqQmFqYXMgcG9yIE1vdGl2byB5IEfDqW5lcm8qKgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KYmFqYXNfcG9yX21vdGl2b19nZW5lcm8gPC0gZGYgJT4lCiAgZ3JvdXBfYnkoYE1vdGl2byBkZSBCYWphYCwgR8OpbmVybykgJT4lCiAgc3VtbWFyaXNlKFRvdGFsX0JhamFzID0gbigpKQoKZ2dwbG90KGJhamFzX3Bvcl9tb3Rpdm9fZ2VuZXJvLCBhZXMoeCA9IGBNb3Rpdm8gZGUgQmFqYWAsIHkgPSBUb3RhbF9CYWphcywgZmlsbCA9IEfDqW5lcm8pKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZSA9ICJCYWphcyBwb3IgTW90aXZvIHkgR8OpbmVybyIsIHggPSAiTW90aXZvIGRlIEJhamEiLCB5ID0gIlRvdGFsIGRlIEJhamFzIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCgpgYGAKCkxhcyBncsOhZmljYXMgbXVlc3RyYW4gcXVlIGxvcyBkZXBhcnRhbWVudG9zIGRlIFByb2R1Y2Npw7NuIGRlIENhcnTDs24sIHRhbnRvIE1DIGNvbW8gTUwsIHJlZ2lzdHJhbiBlbCBtYXlvciBuw7ptZXJvIGRlIGJhamFzIGVuIGxhIGVtcHJlc2EuIEVzdGUgZGF0byByZXNhbHRhIGxhIGV4aXN0ZW5jaWEgZGUgdW4gcHJvYmxlbWEgc2lnbmlmaWNhdGl2byBlbiBlc3RhcyDDoXJlYXMsIHN1YnJheWFuZG8gbGEgdXJnZW5jaWEgZGUgaW52ZXN0aWdhciBsYXMgY2F1c2FzIHN1YnlhY2VudGVzIHBhcmEgaW1wbGVtZW50YXIgZXN0cmF0ZWdpYXMgY29ycmVjdGl2YXMgYWRlY3VhZGFzLgoKQWRlbcOhcywgZXMgbm90YWJsZSBxdWUsIGRlIGxhcyAxOCBwZXJzb25hcyBxdWUgZGVqYXJvbiBsYSBlbXByZXNhLCAxNyBmdWVyYW4gbXVqZXJlcy4gRXN0ZSBkZXNwcm9wb3JjaW9uYWRvIGltcGFjdG8gc29icmUgbGFzIHRyYWJhamFkb3JhcyBzdWdpZXJlIGxhIHByZXNlbmNpYSBkZSB1biBwcm9ibGVtYSBzZXJpbyByZWxhY2lvbmFkbyBjb24gY3Vlc3Rpb25lcyBkZSBnw6luZXJvLiBJZGVudGlmaWNhciB5IGFib3JkYXIgbGFzIGRpbsOhbWljYXMgbyBjb25kaWNpb25lcyBsYWJvcmFsZXMgcXVlIHB1ZWRhbiBlc3RhciBjb250cmlidXllbmRvIGEgZXN0YSBzaXR1YWNpw7NuIGVzIGNydWNpYWwgcGFyYSBjcmVhciB1biBlbnRvcm5vIGRlIHRyYWJham8gbcOhcyBpbmNsdXNpdm8geSBlcXVpdGF0aXZvLgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGYkYEZlY2hhIGRlIEJhamFgIDwtIGFzLkRhdGUoZGYkYEZlY2hhIGRlIEJhamFgLCBvcmlnaW4gPSAiMTg5OS0xMi0zMCIpCgpkZiRBw7FvTWVzIDwtIGZvcm1hdChkZiRgRmVjaGEgZGUgQmFqYWAsICIlWS0lbSIpCmBgYAoKCiMjIyMjICoqVGVuZGVuY2lhIGRlIEJhamFzIGEgbG8gTGFyZ28gZGVsIFRpZW1wbyoqCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpiYWphc19wb3JfZmVjaGEgPC0gZGYgJT4lCiAgZ3JvdXBfYnkoQcOxb01lcykgJT4lCiAgc3VtbWFyaXNlKFRvdGFsX0JhamFzID0gbigpKQoKZ2dwbG90KGJhamFzX3Bvcl9mZWNoYSwgYWVzKHggPSBBw7FvTWVzLCB5ID0gVG90YWxfQmFqYXMsIGdyb3VwID0gMSkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9wb2ludCgpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiVGVuZGVuY2lhIGRlIEJhamFzIGEgbG8gTGFyZ28gZGVsIFRpZW1wbyIsIHggPSAiQcOxbyB5IE1lcyIsIHkgPSAiVG90YWwgZGUgQmFqYXMiKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKCmBgYAoKIyMjIyMgKipCYWphcyBUb3RhbGVzIHBvciBNZXMqKgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCmRmJGBGZWNoYSBkZSBCYWphYCA8LSBhcy5EYXRlKGRmJGBGZWNoYSBkZSBCYWphYCwgb3JpZ2luID0gIjE4OTktMTItMzAiKQoKYmFqYXNfcG9yX21lcyA8LSBkZiAlPiUKICBtdXRhdGUoTWVzID0gZm9ybWF0KGBGZWNoYSBkZSBCYWphYCwgIiVCIikpICU+JQogIGdyb3VwX2J5KE1lcykgJT4lCiAgc3VtbWFyaXNlKFRvdGFsX0JhamFzID0gbigpKQoKbWVzZXMgPC0gZm9ybWF0KHNlcShhcy5EYXRlKCIyMDAwLTAxLTAxIiksIGFzLkRhdGUoIjIwMDAtMTItMDEiKSwgYnkgPSAibW9udGgiKSwgIiVCIikKYmFqYXNfcG9yX21lcyRNZXMgPC0gZmFjdG9yKGJhamFzX3Bvcl9tZXMkTWVzLCBsZXZlbHMgPSBtZXNlcykKCiMgQWhvcmEgb3JkZW5hbW9zIGxvcyBkYXRvcyBwYXJhIGVsIGdyw6FmaWNvCmJhamFzX3Bvcl9tZXMgPC0gYmFqYXNfcG9yX21lcyAlPiUKICBtdXRhdGUoTWVzID0gcmVvcmRlcihNZXMsIC1Ub3RhbF9CYWphcykpCgojIEdyw6FmaWNvIGRlIGJhcnJhcyBtb3N0cmFuZG8gbGFzIGJhamFzIHRvdGFsZXMgcG9yIG1lcywgb3JkZW5hZGFzIGRlIG1heW9yIGEgbWVub3IKZ2dwbG90KGJhamFzX3Bvcl9tZXMsIGFlcyh4ID0gTWVzLCB5ID0gVG90YWxfQmFqYXMsIGZpbGwgPSBNZXMpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiQmFqYXMgVG90YWxlcyBwb3IgTWVzIE9yZGVuYWRhcyIsIHggPSAiTWVzIiwgeSA9ICJUb3RhbCBkZSBCYWphcyIpCgpgYGAKCkEgcGVzYXIgZGUgbGEgYXVzZW5jaWEgZGUgZGF0b3MgZGUgbWFyem8gYSBtYXlvLCBsYSBldmlkZW5jaWEgc3VnaWVyZSBxdWUgbm8gc2UgcmVnaXN0cmFyb24gYmFqYXMgZW4gbGEgZW1wcmVzYSBkdXJhbnRlIGVzZSBwZXJpb2RvLiBTaW4gZW1iYXJnbywgc2Ugb2JzZXJ2YSB1biBub3RhYmxlIGF1bWVudG8gZW4gbGFzIGJhamFzIGVuIGp1bmlvLCBsbyBjdWFsIGVzIHNpZ25pZmljYXRpdm8geSBtZXJlY2UgdW5hIGV4cGxvcmFjacOzbiBkZXRhbGxhZGEuIEVzdGUgaW5jcmVtZW50byBwb2Ryw61hIGVzdGFyIHZpbmN1bGFkbyBhIGZhY3RvcmVzIGxlZ2FsZXMgcmVsYWNpb25hZG9zIGNvbiBjb250cmF0b3MgbywgcG9zaWJsZW1lbnRlLCBlc3RhciBhc29jaWFkbyBhIHByb2JsZW1hcyBlc3BlY8OtZmljb3MgZW4gZWwgw6FyZWEgZGUgcHJvZHVjY2nDs24gZGUgY2FydMOzbiwgZGFkbyBxdWUgbGEgbWF5b3LDrWEgZGUgbGFzIGJhamFzIGVzZSBtZXMgc2UgYXRyaWJ1eWVuIGEgZXN0YSDDumx0aW1hIHJhesOzbi4KCkVzIGltcGVyYXRpdm8gbGxldmFyIGEgY2FibyB1biBhbsOhbGlzaXMgbcOhcyBwcm9mdW5kbyBwYXJhIGNvbXByZW5kZXIgY29uIG1heW9yIHByZWNpc2nDs24gbGFzIGNhdXNhcyBzdWJ5YWNlbnRlcyBkZSBlc3RlIGZlbsOzbWVuby4gRGljaG8gYW7DoWxpc2lzIGF5dWRhcsOhIGEgaWRlbnRpZmljYXIgbGFzIMOhcmVhcyBjcsOtdGljYXMgZGUgaW50ZXJ2ZW5jacOzbiB5IGEgZGVzYXJyb2xsYXIgZXN0cmF0ZWdpYXMgZWZlY3RpdmFzIHBhcmEgcHJldmVuaXIgZnV0dXJhcyBiYWphcyBlbiBlc3RvcyBkZXBhcnRhbWVudG9zIGNyw610aWNvcy4KCmBgYHtyfQpiYWphc19wb3JfZXN0YWRvX2NpdmlsIDwtIGRmICU+JQogIGdyb3VwX2J5KGBFc3RhZG8gQ2l2aWxgKSAlPiUKICBzdW1tYXJpc2UoVG90YWxfQmFqYXMgPSBuKCkpICU+JQogIG11dGF0ZShgRXN0YWRvIENpdmlsYCA9IHJlb3JkZXIoYEVzdGFkbyBDaXZpbGAsIC1Ub3RhbF9CYWphcykpCgpnZ3Bsb3QoYmFqYXNfcG9yX2VzdGFkb19jaXZpbCwgYWVzKHggPSBgRXN0YWRvIENpdmlsYCwgeSA9IFRvdGFsX0JhamFzLCBmaWxsID0gYEVzdGFkbyBDaXZpbGApKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiQmFqYXMgcG9yIEVzdGFkbyBDaXZpbCIsIHggPSAiRXN0YWRvIENpdmlsIiwgeSA9ICJUb3RhbCBkZSBCYWphcyIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQpgYGAKClNlIGRlc3RhY2EgY2xhcmFtZW50ZSBxdWUgbGFzIHBlcnNvbmFzIHNvbHRlcmFzIHByZXNlbnRhbiB1bmEgbWF5b3IgdGFzYSBkZSBiYWphcyBlbiBsYSBlbXByZXNhLiBFc3RlIHBhdHLDs24gcG9kcsOtYSBkZWJlcnNlIGEgbGEgbWVub3IgY2FudGlkYWQgZGUgcmVzcG9uc2FiaWxpZGFkZXMgZmFtaWxpYXJlcyBvIGRlcGVuZGllbnRlcyBlY29uw7NtaWNvcywgbG8gcXVlIGxlcyBvdG9yZ2EgbWF5b3IgZmxleGliaWxpZGFkIHBhcmEgdG9tYXIgZGVjaXNpb25lcyBzb2JyZSBzdSBjYXJyZXJhIHByb2Zlc2lvbmFsIHNpbiB0ZW5lciBxdWUgY29uc2lkZXJhciBlbCBpbXBhY3RvIGVuIG90cm9zIG1pZW1icm9zIGRlIHVuYSBmYW1pbGlhLgoKCiMjIyMjICoqQW7DoWxpc2lzIGRlIFNlbnRpbWllbnRvKioKCkxhcyAyIHRlbmRlbmNpYXMgZGUgbGFzIGVtb2Npb25lcyBzb246IFBvc2l0aXZhIG8gTmVnYXRpdmEKCmBgYHtyfQojIEZ1bmNpw7NuIGFqdXN0YWRhIHBhcmEgcHJlcHJvY2VzYXIgdGV4dG8KcHJlcGFyYXJfdGV4dG8gPC0gZnVuY3Rpb24oZGF0b3MsIGNvbHVtbmEpIHsKICBkYXRvcyAlPiUKICAgIHNlbGVjdCghIXN5bShjb2x1bW5hKSkgJT4lCiAgICBtdXRhdGUoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgYXMuY2hhcmFjdGVyKSkgJT4lCiAgICBtdXRhdGUoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgfiBnc3ViKCJcXGQrIiwgIiIsIC4pKSkgJT4lCiAgICB1bm5lc3RfdG9rZW5zKHdvcmQsICEhc3ltKGNvbHVtbmEpKQp9CgojIEZ1bmNpw7NuIGFqdXN0YWRhIHBhcmEgYW7DoWxpc2lzIGRlIHNlbnRpbWllbnRvIHkgd29yZGNsb3VkCmFuYWxpemFyX3lfd29yZGNsb3VkIDwtIGZ1bmN0aW9uKGRhdG9zLCBjb2x1bW5hKSB7CiAgdGV4dG9fcHJlcGFyYWRvIDwtIHByZXBhcmFyX3RleHRvKGRhdG9zLCBjb2x1bW5hKQogIAogICMgT2J0ZW5lciBzZW50aW1pZW50bwogIGVtb2Npb25lc19kZiA8LSB0ZXh0b19wcmVwYXJhZG8gJT4lCiAgICBpbm5lcl9qb2luKGdldF9zZW50aW1lbnRzKCJucmMiKSwgYnkgPSAid29yZCIpICU+JQogICAgY291bnQoc2VudGltZW50LCBzb3J0ID0gVFJVRSkgJT4lCiAgICBwcmludCgpCiAgCiAgIyBGaWx0cmFyIHBhbGFicmFzIHBhcmEgZWwgd29yZGNsb3VkIChhcGFyaWNpw7NuIG3DrW5pbWE6IDMgdmVjZXMpCiAgcGFsYWJyYXNfZnJlY3VlbnRlcyA8LSB0ZXh0b19wcmVwYXJhZG8gJT4lCiAgICBjb3VudCh3b3JkLCBzb3J0ID0gVFJVRSkgJT4lCiAgICBmaWx0ZXIobiA+PSAzKQogIAogICMgR2VuZXJhciB3b3JkY2xvdWQKICBzZXQuc2VlZCgxMjMpCiAgd29yZGNsb3VkKHdvcmRzID0gcGFsYWJyYXNfZnJlY3VlbnRlcyR3b3JkLCBmcmVxID0gcGFsYWJyYXNfZnJlY3VlbnRlcyRuLCBtaW4uZnJlcSA9IDIsCiAgICAgICAgICAgIG1heC53b3JkcyA9IDEwMCwgcmFuZG9tLm9yZGVyID0gRkFMU0UsIHJvdC5wZXIgPSAwLjM1LCAKICAgICAgICAgICAgY29sb3JzID0gYnJld2VyLnBhbCg4LCAiRGFyazIiKSkKfQpgYGAKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmFuYWxpemFyX3lfd29yZGNsb3VkKGRhdG9zLCAicmF6b25fZW50cmFkYSIpCmBgYApgYGB7cn0KYW5hbGl6YXJfeV93b3JkY2xvdWQoZGF0b3MsICJtb2xlc3RpYXNfcHVlc3RvIikKYGBgCgpgYGB7cn0KYW5hbGl6YXJfeV93b3JkY2xvdWQoZGF0b3MsICJzZW50aW1pZW50b19mb3JtIikKYGBgCgpFbCBhbsOhbGlzaXMgZGVsIHNlbnRpbWllbnRvIGdlbmVyYWwgcmV2ZWxhIHVuYSBhY3RpdHVkIHBvc2l0aXZhIGRlbnRybyBkZSBsYSBlbXByZXNhLCBwcm9iYWJsZW1lbnRlIGluZmx1ZW5jaWFkYSBwb3IgZWwgbcOpdG9kbyBkZSByZWNvbGVjY2nDs24gZGUgZGF0b3MgdXRpbGl6YWRvLCBxdWUgc2UgYmFzw7MgZW4gdW5hIHByZWd1bnRhIGFiaWVydGEgcmVzcG9uZGlkYSBwb3IgbG9zIGNvbGFib3JhZG9yZXMuIFNlIHN1Z2llcmUgcXVlIGVzdGUgZm9ybWF0byBwdWVkZSBoYWNlciBxdWUgc2VhIG3DoXMgZGlmw61jaWwgcGFyYSBsb3MgZW1wbGVhZG9zIGV4cHJlc2FyIHNlbnRpbWllbnRvcyBuZWdhdGl2b3MgZGUgZm9ybWEgY29uY2lzYSwgZW4gdGFuIHNvbG8gdHJlcyBwYWxhYnJhcywgbG8gcXVlIHBvZHLDrWEgbGxldmFyIGEgdW5hIHJlcHJlc2VudGFjacOzbiBtw6FzIHBvc2l0aXZhIGRlbCBhbWJpZW50ZSBsYWJvcmFsIGVuIGxvcyByZXN1bHRhZG9zIGRlbCBhbsOhbGlzaXMuCgojIyMgKiplLiBQcm9uw7NzdGljbyBkZSB2ZW50YXMgKGUuZy4sIHVuaWRhZGVzIGRlIHByb2R1Y2Npw7NuLCB2ZW50YXMgZW4gXCQpKioKCmBgYHtyfQp0c19wbG90KFZlbnRhcykKYGBgCgojIyMgKipJbnRlcnByZXRhY2nDs24qKiBJbnRlcnByZXRhciBsb3MgaGFsbGF6Z29zIGlkZW50aWZpY2Fkb3MgZW4gZWwgZGVzYXJyb2xsbyBkZSBFREEgcGFyYSByZXNwb25kZXIgbGFzIHByZWd1bnRhcyBkZSBhbsOhbGlzaXMuCgpMYSBpbnRlcnByZXRhY2nDs24gY29tcHJlbnNpdmEgZGUgbG9zIGhhbGxhemdvcyByZXZlbGEgdW5hIGNvbXBsZWppZGFkIHN1YnlhY2VudGUgZW4gbGEgcGVyY2VwY2nDs24geSByZWFsaWRhZGVzIGRlbCBhbWJpZW50ZSBsYWJvcmFsIGVuIGxhIGVtcHJlc2EgRk9STS4gQSBwZXNhciBkZSBsYSBhcGFyZW50ZSBhY3RpdHVkIHBvc2l0aXZhIGdlbmVyYWwsIHNlIGlkZW50aWZpY2FuIGRlc2Fmw61vcyBlc3BlY8OtZmljb3MgeSBvcG9ydHVuaWRhZGVzIGRlIG1lam9yYS4gUHJpbmNpcGFsZXMgaW5zaWdodHMgeSByZWNvbWVuZGFjaW9uZXMgaW5jbHV5ZW46CgotICoqSW5zaWdodHMgUHJpbmNpcGFsZXM6KioKICAtIExhIG1ldG9kb2xvZ8OtYSBkZSByZWNvbGVjY2nDs24gZGUgZGF0b3MgcHVlZGUgaW5mbHVpciBlbiBsYSBwZXJjZXBjacOzbiBwb3NpdGl2YSBnZW5lcmFsIGRlbCBhbWJpZW50ZSBsYWJvcmFsLCBzdWdpcmllbmRvIGxhIHBvc2liaWxpZGFkIGRlIHVuIHNlc2dvIGVuIGxhcyByZXNwdWVzdGFzIG9idGVuaWRhcy4KICAtIExhcyBhbHRhcyB0YXNhcyBkZSBiYWphIGVudHJlIGVsIHBlcnNvbmFsIHNvbHRlcm8geSBsb3MgZGVwYXJ0YW1lbnRvcyBlc3BlY8OtZmljb3MsIGNvbW8gUHJvZHVjY2nDs24gZGUgQ2FydMOzbiwgYXB1bnRhbiBhIG5lY2VzaWRhZGVzIHkgcHJlb2N1cGFjaW9uZXMgw7puaWNhcyBlbiBlc3RhcyBwb2JsYWNpb25lcy4KICAtIFVuYSBkZXNwcm9wb3JjacOzbiBzaWduaWZpY2F0aXZhIGVuIGxhcyBiYWphcyBkZSBtdWplcmVzIHJlc2FsdGEgcHJvYmxlbWFzIHBvdGVuY2lhbGVzIGRlIGfDqW5lcm8gcXVlIG5lY2VzaXRhbiBzZXIgYWJvcmRhZG9zIHBhcmEgbWVqb3JhciBsYSBlcXVpZGFkIGVuIGVsIGx1Z2FyIGRlIHRyYWJham8uCiAgLSBMYSBjb3JyZWxhY2nDs24gcG9zaXRpdmEgZW50cmUgbGEgYW50aWfDvGVkYWQgeSBsYSBzYXRpc2ZhY2Npw7NuIHNhbGFyaWFsIGVuZmF0aXphIGxhIGltcG9ydGFuY2lhIGRlIGxhcyBwb2zDrXRpY2FzIGRlIHJldGVuY2nDs24geSByZWNvbXBlbnNhIGJhc2FkYXMgZW4gbGEgbGVhbHRhZCB5IGVsIHRpZW1wbyBkZSBzZXJ2aWNpby4KCi0gKipSZWNvbWVuZGFjaW9uZXMgR2VuZXJhbGVzIHBhcmEgbGEgRW1wcmVzYSBGT1JNOioqCiAgLSAqKk1lam9yYXIgbGFzIENvbmRpY2lvbmVzIGRlIFRyYWJham86KiogUHJpb3JpemFyIGxhIHJlZ3VsYWNpw7NuIGRlIGxhIHRlbXBlcmF0dXJhIGVuIMOhcmVhcyBjcsOtdGljYXMgeSBleGFtaW5hciBvdHJhcyBjb25kaWNpb25lcyBsYWJvcmFsZXMgcXVlIHB1ZWRlbiBlc3RhciBhZmVjdGFuZG8gbmVnYXRpdmFtZW50ZSBsYSBzYXRpc2ZhY2Npw7NuIGRlbCBlbXBsZWFkby4KICAtICoqQWp1c3RhciBsYSBFc3RydWN0dXJhIFNhbGFyaWFsOioqIENvbnNpZGVyYXIgcmV2aXNpb25lcyBlbiBsYSBlc3RydWN0dXJhIHNhbGFyaWFsIHBhcmEgbWVqb3JhciBsYSBzYXRpc2ZhY2Npw7NuIGVudHJlIGxvcyBlbXBsZWFkb3MgZGUgbWVub3IgYW50aWfDvGVkYWQsIHBvdGVuY2lhbG1lbnRlIHJlZHVjaWVuZG8gbGEgcm90YWNpw7NuLgogIC0gKipFbmZvY2Fyc2UgZW4gbGEgRXF1aWRhZCBkZSBHw6luZXJvOioqIEltcGxlbWVudGFyIHBvbMOtdGljYXMgZXNwZWPDrWZpY2FzIHBhcmEgYWJvcmRhciB5IG1lam9yYXIgbGFzIGRpbsOhbWljYXMgZGUgZ8OpbmVybywgYXNlZ3VyYW5kbyB1biBlbnRvcm5vIGRlIHRyYWJham8gaW5jbHVzaXZvIHkgZXF1aXRhdGl2byBwYXJhIHRvZG9zIGxvcyBlbXBsZWFkb3MuCgpFc3RhcyByZWNvbWVuZGFjaW9uZXMgYXB1bnRhbiBhIGZvcnRhbGVjZXIgZWwgYW1iaWVudGUgbGFib3JhbCBlbiBGT1JNLCBhYm9yZGFuZG8gdGFudG8gbG9zIGRlc2Fmw61vcyBpZGVudGlmaWNhZG9zIGNvbW8gYXByb3ZlY2hhbmRvIGxhcyDDoXJlYXMgZGUgZm9ydGFsZXphIHBhcmEgZm9tZW50YXIgdW4gZW50b3JubyBtw6FzIHBvc2l0aXZvIHkgcHJvZHVjdGl2by4KCiMjIELDunNxdWVkYSBkZSBpbmZvcm1hY2nDs24geSBkYXRvcwoKLSAgIMK/UXXDqSB0aXBvIGRlIGluZm9ybWFjacOzbiAvIGRhdG9zIHNvbGljaXRhcsOtYXMgYWwgc29jaW8gZm9ybWFkb3IgcGFyYSBtZWpvcmFyIEVEQT8gCgpQYXJhIHBvZGVyIHRlbmVyIHVuIEFuw6FsaXNpcyBFeHBsb3JhdG9yaW8gZGUgbG9zIERhdG9zIGNvbXBsZXRvLCBkZWJlbW9zIGRlIGRlc2Fycm9sbGFyIHNvbHVjaW9uZXMgZWZlY3RpdmFzIGEgbG9zIHByb2JsZW1hcyBkZSBsYSBlbXByZXNhLCBwcmluY2lwYWxtZW50ZSBlbiBsYSByb3RhY2nDs24gZGUgcGVyc29uYWwgeSBsYSBwcmVkaWNjacOzbiBkZSBsYSBkZW1hbmRhIGVuIHByb2R1Y2Npw7NuIGVzIHBvciBlc28gcXVlIHBlZGlyw61hbW9zIGluZm9ybWFjacOzbiBjb21vOgoKMS4gIEluZm9ybWFjacOzbiBkZXRhbGxhZGEgc29icmUgbGFzIGJhc2VzIGRlIGRhdG9zLCBjb21vIGJhc2UgZGUgZGF0b3MgY29tcGxldGEgZGUgcGVyc29uYWwuIFRhbWJpw6luLCBlbiBsYSBiYXNlIGRlIGRhdG9zIGRlIHZlbnRhcyBpbmNsdWlyIG3DoXMgaW5mb3JtYWNpw7NuLCB5YSBxdWUgY3VlbnRhIGNvbiBOQSwgbG8gcXVlIGhhY2UgY29tcGxpY2FjaW9uZXMgZW4gZWwgYW7DoWxpc2lzLCBxdWUgbm8gcG9kYW1vcyB0cmFiYWphciBjb24gbXV5IHBvY29zIGRhdG9zIHkgZXNvIGxpbWl0YSBudWVzdHJvIHRyYWJham8gcGFyYSBwb2RlciBzZWd1aXIgaWRlbnRpZmljYW5kbyBoYWxsYXpnb3MgaW1wb3J0YW50ZXMgcGFyYSBsYSBlbXByZXNhCgoyLiAgRGF0YSBkZSBlbmN1ZXN0YXMgZGUgYmFqYXMsIHNvYnJlIHRvZG8gaW5jbHV5ZW5kbyBsYXMgcmF6b25lcyBkZSBsYSByZW51bmNpYSBwYXJhIHBvZGVyIGRldGVjdGFyIGRpZmVyZW50ZXMgdGVuZGVuY2lhcyB5IHBhdHJvbmVzLgoKMy4gIFVuIEFuw6FsaXNpcyBEZW1vZ3LDoWZpY28gcGFyYSBzYWJlciBkYXRvcyBkZSBsYSBlZGFkLCBnw6luZXJvLCBzaXR1YWNpw7NuIGZhbWlsaWFyIHkgdWJpY2FjacOzbiBnZW9ncsOhZmljYSBkZSBsb3MgZW1wbGVhZG9zIHBhcmEgcG9kZXIgcmVsYWNpb25hciBwYXRyb25lcyBjb24gbGEgcm90YWNpw7NuIHF1ZSBleGlzdGUgZW4gRk9STS4KCkRlIGZvcm1hIG3DoXMgc2ltcGxlLCBsb3MgZGF0b3MgZXhwbGljaXRvcyBtw6FzIG5lY2VzYXJpb3Mgc29uOiAKLeKBoCAqKuKBoEJBU0UgREFUT1MgQ09NUExFVEEgREUgUEVSU09OQUwqKgot4oGgICoq4oGgREFUQSBERSBFTkNVRVNUQVMgREUgUkFaT04gREUgQkFKQVMqKgot4oGgICoq4oGgREFUQSBERSBUSUVNUE9TIERFIElOVkVOVEFSSU8qKgot4oGgICoq4oGgREFUQSBERSBERVNHTE9TRSBERSBWRU5UQSBERSBVTklEQURFUyBQT1IgQ0xJRU5URSAvIE8gUE9SIFRJUE8gREUgUEFSVEUqKgoKLSAgIMK/UXXDqSB0aXBvIGRlIGluZm9ybWFjacOzbiAvIGRhdG9zIGRlIGZ1ZW50ZXMgc2VjdW5kYXJpYXMgYnVzY2Fyw61hcyBwYXJhIG1lam9yYXIgRURBPwoKUGFyYSBjb21wbGVtZW50YXIgZWwgRURBLCBjb24gaW5mb3JtYWNpw7NuIGRlIGZ1ZW50ZXMgZXh0ZXJuYXMsIGJ1c2NhbW9zIGluZm9ybWFjacOzbiBlbjoKCjEuICBJbmZvcm1lcyBkZSBsYSBJbmR1c3RyaWEgKFN0YXRpc3RhKSBkZWJpZG8gYSBxdWUgbm9zIHByb3BvcmNpb25hIGVzdGFkw61zdGljYXMgZ2xvYmFsZXMgc29icmUgbGEgaW5kdXN0cmlhIGF1dG9tb3RyaXouIGluY2x1eWVuZG8gbGFzIHRlbmRlbmNpYXMgdGVjbm9sw7NnaWNhcy4KCjIuICBFc3R1ZGlvcyBzb2JyZSBlbCBtZXJjYWRvIGRlIGxvcyBlbXBhcXVlcyAoU21pdGhlcnMpIHB1YmxpY2FuIGFuw6FsaXNpcyBkZSB0ZW5kZW5jaWFzIGUgaW5mb3JtZXMgZGUgbWVyY2FkbyBkZSBsb3MgZW1wYXF1ZXMgcXVlIHNlIHV0aWxpemFuIGVuIGVsIHNlY3RvciBhdXRvbW90cml6LgoKMy4gIERhdG9zIGRlIENvbWVyY2lvIEludGVybmFjaW9uYWwgeSBlY29uw7NtaWNvcyAoQmFuY28gTXVuZGlhbCkgcGFyYSBsb3MgZGF0b3MgZGUgdGFyaWZhcyB5IGVjb25vbcOtYSBnbG9iYWwgcXVlIGFmZWN0YW4gZWwgY29tZXJjaW8gZGUgbG9zIGVtcGFxdWVzCgo0LiAgKEhvb3ZlcnMpIHBhcmEgdW4gQW7DoWxpc2lzIGRlIENvbXBldGVuY2lhLCBkb25kZSBzZSBvZnJlY2VuIGRhdG9zIGltcG9ydGFudGVzIHNvYnJlIGxhcyBlbXByZXNhcyB5IHVuIGFuw6FsaXNpcyBkZXRhbGxhZG8gZGUgY29tcGV0aWRvcmVzIGVuIGxhIGluZHVzdHJpYSBkZSBlbXBhcXVlcy4KCi0gICAoT3BjaW9uYWwpIEJ1c2NhciBpbmZvcm1hY2nDs24gLyBkYXRvcyBkZSBmdWVudGVzIHNlY3VuZGFyaWFzIChwb3IgZWplbXBsbywgSU5FR0ksIEluZHVzdHJpYSBOYWNpb25hbCBkZSBBdXRvcGFydGVzLCBldGMuKSBxdWUgY29udHJpYnV5YW4gYSBtZWpvcmFyIEVEQSB5IGxhIGlkZW50aWZpY2FjacOzbiBkZSBoYWxsYXpnb3MgcmVsZXZlbnRlcyBxdWUgcmVzcG9uZGFuIGxhcyBwcmVndW50YXMgZGUgYW7DoWxpc2lzLiBDaXRhciBsYXMgZnVlbnRlcyBzZWN1bmRhcmlhcyBzZWxlY2Npb25hZGFzLgoKUGFyYSB0ZW5lciB1biBhbsOhbGlzaXMgbcOhcyBkZXRhbGxhZG8gYnVzY2Ftb3MgaW5mb3JtYWNpw7NuIGVuIGRpZmVyZW50ZXMgZnVlbnRlczoKCioqMS4qKiAgQ3JlY2ltaWVudG8gZGVsIFNlY3RvciBBdXRvbW90cml6LCBlbiBlbCAyMDI0IHNlIGVzcGVyYSBxdWUgbGEgY2lmcmEgZGUgdmVow61jdWxvcyBjb21lcmNpYWxpemFkb3MgZW4gTcOpeGljbyBpbmNyZW1lbnRlIGVuIHVuIDglIHkgZXN0byByZXByZXNlbnRhIDEwMCBtaWwgdW5pZGFkZXMgbcOhcyBxdWUgZW4gZWwgMjAyMy4gRW4gMjAyMyB0dXZvIHVuIGNyZWNpbWllbnRvIGRlbCAyNC40JSBlbiB2ZWjDrWN1bG9zIGNvbWVyY2lhbGl6YWRvcyBjb21wYXJhZG8gY29uIGVsIDIwMjIuIChNZXhpY28gSW5kdXN0cnksIDIwMjQpLiBFc3RvcyBkYXRvcyBzb24gdW4gcG90ZW5jaWFsIGF1bWVudG8gZGUgZGVtYW5kYSBlbiBsb3MgZW1wYXF1ZXMgZGUgYXV0b3BhcnRlcyBsbyBxdWUgZXMgdW4gaW1wYWN0byBwb3NpdGl2byBwYXJhIEZPUk0uCgoqKjIuKiogIEltcGFjdG8gZW4gbGEgZWxlY3Ryb21vdmlsaWRhZCwgeWEgcXVlIGV4aXN0ZSB1bmEgdHJhbnNpY2nDs24gaGFjaWEgbGEgZWxlY3Ryb21vdmlsaWRhZCB5IGVzdG8gZ2VuZXJhIHVuYSBvcG9ydHVuaWRhZCBwYXJhIGxhIGNyZWFjacOzbiBkZSBlbXBsZW9zIHkgbGEgZGVtYW5kYSBkZSBjb21wZXRlbmNpYXMgZXNwZWNpYWxpemFkYXMsIGVzdG8gaW1wYWN0YSBlIGluZmx1eWUgZGUgbWFuZXJhIHNpZ25pZmljYXRpdmEgYSBsYSBkZW1hbmRhIGRlIGVtcGFxdWVzIHBhcmEgbG9zIGF1dG9wYXJ0ZXMgeSBjb21wb25lbnRlcyBlbGVjdHLDs25pY29zIHkgc2lzdGVtYXMgYXZhbnphZG9zIGVuIGxvcyBhdXRvbcOzdmlsZXMuCgoKIyNSZWZlcmVuY2lhcyAKCiMxLiAqRCZCIEhvb3ZlcnMgaXMgWW91ciBTYWxlcyBBY2NlbGVyYXRvciAtLSBEdW4gJiBCcmFkc3RyZWV0Ki4gKHMuIGYuKS4gUmVjdXBlcmFkbyAxNiBkZSBtYXJ6byBkZSAyMDI0LCBkZSA8aHR0cHM6Ly93d3cuZG5iLmNvbS9wcm9kdWN0cy9kbmItaG9vdmVycy5odG1sPiAKCiMyLiAqV29ybGQgQmFuayBHcm91cCAtIEludGVybmF0aW9uYWwgRGV2ZWxvcG1lbnQsIFBvdmVydHksICYgU3VzdGFpbmFiaWxpdHkqLiAocy4gZi4pLiBXb3JsZCBCYW5rLiBSZWN1cGVyYWRvIDE2IGRlIG1hcnpvIGRlIDIwMjQsIGRlIDxodHRwczovL3d3dy53b3JsZGJhbmsub3JnL2VuL2hvbWU+IAoKIzMuICpTbWl0aGVycyAtIElubm92YXRlIHdpdGggY29uZmlkZW5jZSouIChzLiBmLikuIFNtaXRoZXJzLiBSZWN1cGVyYWRvIDE2IGRlIG1hcnpvIGRlIDIwMjQsIGRlIDxodHRwczovL3d3dy5zbWl0aGVycy5jb20vaG9tZT4gCgojNC4gKlN0YXRpc3RhLiAocy4gZi4pLiBTdGF0aXN0YSAtIHRoZSBzdGF0aXN0aWNzIHBvcnRhbCouIFJlY3VwZXJhZG8gMTYgZGUgbWFyem8gZGUgMjAyNCwgZGUgPGh0dHBzOi8vd3d3LnN0YXRpc3RhLmNvbS8+IAoKIzUuICpNZXhpY29JbmR1c3RyeS4gKHMuIGYuKS4gKkluY3JlbWVudGFyw6EgOCUgZWwgc2VjdG9yIGF1dG9tb3RyaXogZW4gMjAyNCouIE1leGljb0luZHVzdHJ5LiBSZWN1cGVyYWRvIDE2IGRlIG1hcnpvIGRlIDIwMjQsIGRlIDxodHRwczovL21leGljb2luZHVzdHJ5LmNvbS9ub3RpY2lhL2luY3JlbWVudGFyYS04LWVsLXNlY3Rvci1hdXRvbW90cml6LWVuLTIwMjQ+IAoKIzYuICpOZXdzcm9vbSBJbmZvYmFlLiAoMjAyMywgMTIgYWJyaWwpLiBJbmR1c3RyaWEgYXV0b21vdHJpeiBlbiBNw6l4aWNvIGVzcGVyYSBtw6FzIGVtcGxlb3MgcG9yIGVsZWN0cm9tb3ZpbGlkYWQuICpJbmZvYmFlKi4gUmVjdXBlcmFkbyAxNiBkZSBtYXJ6byBkZSAyMDI0LCBkZSA8aHR0cHM6Ly93d3cuaW5mb2JhZS5jb20vYW1lcmljYS9hZ2VuY2lhcy8yMDIzLzA0LzEyL2luZHVzdHJpYS1hdXRvbW90cml6LWVuLW1leGljby1lc3BlcmEtbWFzLWVtcGxlb3MtcG9yLWVsZWN0cm9tb3ZpbGlkYWQvPgoK